You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@chemistry.apache.org by David Caruana <da...@alfresco.com> on 2010/10/12 12:49:02 UTC

Proposal to clarify CmisObject caching behaviour

Currently, we only have one implementation of Session - PersistentSessionImpl. However, the OpenCMIS client API suggests transient behaviour both in its API definition and behaviour, which I believe can be confusing for users. In particular, when does OpenCMIS read information from the cache vs from the repository, and when does OpenCMIS implicitly update an item in its cache.

I'd like to present the following changes in an attempt to clarify the above and trigger discussion on how to improve things in this area...

1) All methods on CmisObject operate against the cache. This means that reading a value from an item reads the value from the item in the cache, and updates to the item change the cache i.e. refresh the item in the cache. Methods that read directly from the repository move to Session. So, the proposal is:

Remove the following from CmisObject...
CmisObject.setName(String)      
CmisObject.setProperty(String, Object)    
CmisObject.updateProperties()

Change CmisObject.updateProperties...
CmisObject CmisObject.updateProperties(Map<String, ?>)    (Note: return CmisObject instead of ObjectId)

Note: If the repository creates a new version, a new CmisObject is returned, otherwise the existing CmisObject is refreshed in the cache and returned.

The following 'update' methods are also modified to refresh the item in the cache after update:

void CmisObject.applyPolicy(ObjectId...)    (Note: accept vararg of policy ids)
void CmisObject.removePolicy(ObjectId...)   (Note: accept vararg of policy ids)
Acl CmisObject.applyAcl(List<Ace>, List<Ace>, AclPropagation)
Acl CmisObject.addAcl(List<Ace>, AclPropagation)   (Note: also return Acl to be consistent with applyAcl)
Acl CmisObject.removeAcl(List<Ace>, AclPropagation)   (Note: also return Acl to be consistent with applyAcl)

Note: applyPolicy and removePolicy are also changed to accept a vararg of ObjectIds.

For use cases where the refresh of an item after update is not necessary, the Session interface is used instead. So, the proposal is...

Move following methods from CmisObject to Session...

ItemIterable<Relationship> Session.getRelationships(ObjectId, boolean, RelationshipDirection, ObjectType, OperationContext)
Acl Session.getAcl(ObjectId, boolean)

Add...

ObjectId Session.updateProperties(ObjectId, Map<String, ?>)
void applyPolicy(ObjectId, ObjectId...)
void removePolicy(ObjectId, ObjectId...)
Acl applyAcl(ObjectId, List<Ace> addAces, List<Ace> removeAces, AclPropagation aclPropagation)
Acl getAcl(ObjectId, boolean onlyBasicPermissions)

2) Following the pattern in 1), setting content on a Document alters slightly too.

Document setContentStream(ContentStream contentStream, boolean overwrite)
Document deleteContentStream()

Instead of returning ObjectId, the proposal is to return Document. Depending on the repository, the document may be the same item as before (updated in the cache), or a new Document, to represent a new version.

Also add to Session...

ObjectId setContentStream(ObjectId, ContentStream contentStream, boolean overwrite)
ObjectId deleteContentStream(ObjectId)

3) Remove transient methods from Session.

Until we've thought through transient session behaviour I propose we remove the following methods:

Session.save()
Session.cancel()

Regards,
Dave

Re: Proposal to clarify CmisObject caching behaviour

Posted by Florian Müller <fl...@alfresco.com>.
Yes, sounds reasonable. I will create a branch.

- Florian

On 10/11/2010 19:41, Florent Guillaume wrote:
> Could you do it in a branch for a few days?
> I have a fix to do for the AtomPub bindings (they generate bad atom
> alternate links for renditions), and I'll need it for the Nuxeo server
> bindings shortly. I'd rather not change the updateProperties / save
> that I may be using right now in our connector's code. In a 1-2 days
> I'll commit and make a private snapshot and we can merge your branch.
> Is that ok?
>
> Florent
>
> On Wed, Nov 10, 2010 at 8:35 PM, Florian Müller
> <fl...@alfresco.com>  wrote:
>> Got it. Thanks.
>>
>> Would somebody object if I would start the refactoring?
>> If we don't like it, we can roll it back.
>>
>> I would also remove the "persistent" and "transient" notion from the session
>> implementation including renaming those classes.
>>
>>
>> - Florian
>>
>>
>>
>> On 10/11/2010 17:43, Florent Guillaume wrote:
>>>
>>> It would be an interface.
>>>
>>> I agree that it's not obvious in this case that transient behavior can
>>> be obtained using an adapter (and autocompletion doc.get... does not
>>> immediately provide it). But this can be solved by simple
>>> documentation I think. Yes if we think transient documents are
>>> fundamental we can make createTransientDocument a synonym to get this
>>> adapter. It's not mandatory though.
>>>
>>> Florent
>>>
>>> On Wed, Nov 10, 2010 at 3:16 PM, Florian Müller
>>> <fl...@alfresco.com>    wrote:
>>>>
>>>> Hi Florent,
>>>>
>>>> Could you elaborate a bit more on that proposal?
>>>> Would TransientDocument.class be an Interface or a Class?
>>>>
>>>> I like the idea of adapters. But it is not intuitive that there is an
>>>> adapter the provides a transient paradigm. Would it make sense to add
>>>> another method that provides a shortcut to the "transient adapter"?
>>>>
>>>>
>>>> Thanks,
>>>>
>>>> Florian
>>>>
>>>>
>>>> On 10/11/2010 13:27, Florent Guillaume wrote:
>>>>>
>>>>> I've come around to agreeing that 2. is probably better.
>>>>>
>>>>> I can see either:
>>>>>    TransientDocument transDoc = doc.createTransientDocument():
>>>>> or
>>>>>    TransientDocument transDoc = doc.getAdapter(TransientDocument.class);
>>>>>
>>>>> The latter is more extensible for other uses besides transience
>>>>> (protocol extensions, application-specific adapters).
>>>>>
>>>>> WDYT?
>>>>>
>>>>> Florent
>>>>>
>>>>>
>>>>> On Wed, Nov 10, 2010 at 10:41 AM, Florian Müller
>>>>> <fl...@alfresco.com>      wrote:
>>>>>>
>>>>>> I would like to see that sorted out soon. There are more and more users
>>>>>> of OpenCMIS and API changes are usually painful for them. We should
>>>>>> also
>>>>>> consider a new release (0.2.0) when this is done.
>>>>>>
>>>>>> So, where are we?
>>>>>>
>>>>>> The main question is where we want to handle transient data. We have
>>>>>> two
>>>>>> opinions:
>>>>>> 1. Transient and non-transient data access should be covered by the
>>>>>> CmisObject interface. (Florent)
>>>>>> 2. Transient data access should be covered by a new interface and
>>>>>> non-transient data access should be covered by the CmisObject
>>>>>> interface.
>>>>>> (Florian)
>>>>>>
>>>>>> Personally, I still want to go for option 2 since it provides cleaner
>>>>>> semantics -- especially in multi-threaded environments.
>>>>>>
>>>>>> Other opinions?
>>>>>>
>>>>>>
>>>>>> - Florian
>>>>>>
>>>>>>
>>>>>> On 08/11/2010 11:51, David Caruana wrote:
>>>>>>>
>>>>>>> Have we reached a conclusion on this issue? It's been a while since we
>>>>>>> last discussed.
>>>>>>>
>>>>>>> Regards,
>>>>>>> Dave
>>>>>>>
>>>>>>> On 22 Oct 2010, at 15:06, Florian Müller wrote:
>>>>>>>
>>>>>>>> Oh, right, there is yet another option. :)
>>>>>>>>
>>>>>>>> I support all your arguments against b), c) and d). But there are
>>>>>>>> also
>>>>>>>> two issues with e).
>>>>>>>> 1. Which value wins if a property is changed in the transient object
>>>>>>>> _and_ present in the map?
>>>>>>>> 2. save() stores the whole object. If we make ACLs and Policies
>>>>>>>> transient too (do we want that?) than updateProperties() has the side
>>>>>>>> effect
>>>>>>>> of storing those as well.
>>>>>>>>
>>>>>>>> Which leaves us with a) which is pretty strong. And in this case I
>>>>>>>> prefer two interfaces because it much is easier to understand and
>>>>>>>> provides
>>>>>>>> more compile checks and less runtime surprises.
>>>>>>>>
>>>>>>>>
>>>>>>>> - Florian
>>>>>>>>
>>>>>>>>
>>>>>>>> On 22/10/2010 14:44, Florent Guillaume wrote:
>>>>>>>>>
>>>>>>>>> On Fri, Oct 22, 2010 at 3:33 PM, Florian Müller
>>>>>>>>> <fl...@alfresco.com>         wrote:
>>>>>>>>>>
>>>>>>>>>> So your proposal is to add a method getTransientObject() (or
>>>>>>>>>> something like that) to CmisObject. And that method would return a
>>>>>>>>>> transient, not thread-safe version of the object but with
>>>>>>>>>> setProperty(),
>>>>>>>>>> save(), etc. enabled?
>>>>>>>>>> Is that correct?
>>>>>>>>>
>>>>>>>>> Yes.
>>>>>>>>>
>>>>>>>>>> In this case we should also add a method isTransient() to
>>>>>>>>>> CmisObject.
>>>>>>>>>> There should be a way to discover the state of the CmisObject.
>>>>>>>>>
>>>>>>>>> Yes that would be useful.
>>>>>>>>>
>>>>>>>>>> I suggest that if the object is not transient, the transient
>>>>>>>>>> methods
>>>>>>>>>> should throw an IllegalStateException.
>>>>>>>>>
>>>>>>>>> Ok.
>>>>>>>>>
>>>>>>>>>> I agree that keeping the number of interfaces and classes low helps
>>>>>>>>>> to learn and understand an API. But blending two semantics in one
>>>>>>>>>> class
>>>>>>>>>> could be even more confusing.
>>>>>>>>>> For example, what should happen if updateProperties(Map) is called
>>>>>>>>>> on
>>>>>>>>>> a transient object? There are multiple options:
>>>>>>>>>>     a) updateProperties(Map) throws an exception because it only
>>>>>>>>>> works
>>>>>>>>>> for non-transient objects.
>>>>>>>>>>     b) updateProperties(Map) writes instantly to the repository and
>>>>>>>>>> the transient object is refreshed.
>>>>>>>>>
>>>>>>>>> (which btw means that transient changes are lost)
>>>>>>>>>>
>>>>>>>>>>     c) updateProperties(Map) writes instantly to the repository and
>>>>>>>>>> but object keep its (now outdated) state.
>>>>>>>>>>     d) The property map is merged with the transient properties and
>>>>>>>>>> written when save() is called.
>>>>>>>>>
>>>>>>>>> And also:
>>>>>>>>> e) The property map is merged with the transient properties and then
>>>>>>>>> save() is automatically called.
>>>>>>>>>
>>>>>>>>>> It is not obvious. All semantics would be right and wrong at the
>>>>>>>>>> same
>>>>>>>>>> time.
>>>>>>>>>
>>>>>>>>> Agreed, we have to make a choice. But we would make a similar choice
>>>>>>>>> when deciding what methods would be available on the
>>>>>>>>> TransientDocument
>>>>>>>>> interface and what they would do.
>>>>>>>>>
>>>>>>>>> But anyway my choices in order of preference would be e) then a).
>>>>>>>>> I don't like b) because it loses changes.
>>>>>>>>> I don't like c) because there's an issue with not keeping the
>>>>>>>>> changes
>>>>>>>>> in order.
>>>>>>>>> I don't like d) because if you didn't do any transient operation it
>>>>>>>>> doesn't behave like its non-transient counterpart.
>>>>>>>>>
>>>>>>>>> Florent
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On 22/10/2010 13:43, Florent Guillaume wrote:
>>>>>>>>>>>
>>>>>>>>>>> Hi,
>>>>>>>>>>>
>>>>>>>>>>> Looking back at your example:
>>>>>>>>>>>
>>>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>>>> transDoc.save();
>>>>>>>>>>>
>>>>>>>>>>> I agree with the need to explicitly getting a transient object if
>>>>>>>>>>> you
>>>>>>>>>>> need different semantics.
>>>>>>>>>>> One thing that will be painful though is having different classes:
>>>>>>>>>>> TransientCmisObject, TransientDocument, TransientFolder, etc.
>>>>>>>>>>> Couldn't we simply have all the methods available on the
>>>>>>>>>>> CmisObject,
>>>>>>>>>>> Document, Folder, etc. and make them throw
>>>>>>>>>>> UnsupportedOperationException when called on a non-transient
>>>>>>>>>>> object?
>>>>>>>>>>> This would tremendously help learning about the API and avoid
>>>>>>>>>>> juggling
>>>>>>>>>>> with many different interfaces for the users.
>>>>>>>>>>>
>>>>>>>>>>> Florent
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
>>>>>>>>>>> <fl...@alfresco.com>           wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> Hi Florent,
>>>>>>>>>>>>
>>>>>>>>>>>> Well, no, there would be no CmisObject.save() method. The save()
>>>>>>>>>>>> method
>>>>>>>>>>>> would only be on the transient object.
>>>>>>>>>>>>
>>>>>>>>>>>> CmisObject would have updateProperties(Map), applyAcl(List<Ace>,
>>>>>>>>>>>> List<Ace>,
>>>>>>>>>>>> AclPropagation), applyPolicy(ObjectId), etc. And all of them
>>>>>>>>>>>> would
>>>>>>>>>>>> write
>>>>>>>>>>>> instantly to the repository and refresh the object.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Florian
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> On 18/10/2010 17:49, Florent Guillaume wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> Ok understood and agreed. There would be a new CmisObject.save()
>>>>>>>>>>>>> to
>>>>>>>>>>>>> replace updateProperties() then? That works for me as it's a
>>>>>>>>>>>>> less
>>>>>>>>>>>>> restrictive name that allows for different implementations of
>>>>>>>>>>>>> the
>>>>>>>>>>>>> transient space that don't deal with just properties.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Regarding your examples I don't need to do all that, because in
>>>>>>>>>>>>> the
>>>>>>>>>>>>> Nuxeo use cases I described the client Session I'm providing to
>>>>>>>>>>>>> the
>>>>>>>>>>>>> user of the API is not a PersistentSessionImpl but a completely
>>>>>>>>>>>>> new
>>>>>>>>>>>>> Nuxeo class that does all the wrapping it needs around native
>>>>>>>>>>>>> Nuxeo
>>>>>>>>>>>>> objects. So I'm not constrained by the semantics of the current
>>>>>>>>>>>>> PersistentSessionImpl. It's just that I need a save()-like API
>>>>>>>>>>>>> to
>>>>>>>>>>>>> exist on the CmisObject. And of course I want to have semantics
>>>>>>>>>>>>> that
>>>>>>>>>>>>> are not too far to what's available when you use an actual
>>>>>>>>>>>>> remote
>>>>>>>>>>>>> connection using pure OpenCMIS PersistentSessionImpl.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Florent
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>>>>>>>>>>>>> <fl...@alfresco.com>             wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi Florent,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> We don't want to remove the transient space entirely. The
>>>>>>>>>>>>>> proposal is to
>>>>>>>>>>>>>> detach the transient from the non-transient part. We would have
>>>>>>>>>>>>>> two
>>>>>>>>>>>>>> separate
>>>>>>>>>>>>>> objects.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> The non-transient object is always consistent, can be shared
>>>>>>>>>>>>>> across
>>>>>>>>>>>>>> threads
>>>>>>>>>>>>>> and is cached. Changes are directly written to the repository.
>>>>>>>>>>>>>> This
>>>>>>>>>>>>>> object
>>>>>>>>>>>>>> would have an updateProperties(Map) method that immediately
>>>>>>>>>>>>>> refreshes the
>>>>>>>>>>>>>> object after the update.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> The transient object is owned by one thread and not thread
>>>>>>>>>>>>>> safe.
>>>>>>>>>>>>>> That
>>>>>>>>>>>>>> should
>>>>>>>>>>>>>> prevent inconsistent views on the object. This object would
>>>>>>>>>>>>>> have
>>>>>>>>>>>>>> setProperty() and save() methods. Internally it would use the
>>>>>>>>>>>>>> non-transient
>>>>>>>>>>>>>> object to access all unchanged data. It's a wrapper around the
>>>>>>>>>>>>>> non-transient
>>>>>>>>>>>>>> object that holds the transient data.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> So you still could use the pattern that you are using today.
>>>>>>>>>>>>>> The
>>>>>>>>>>>>>> only
>>>>>>>>>>>>>> difference would be that you have to create a transient wrapper
>>>>>>>>>>>>>> object.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> That could look like this:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>>>>>>> TransientDocument transDoc = new TransientDocument(doc);
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>>>>>>> transDoc.save(); // that also refreshes the underlying
>>>>>>>>>>>>>> non-transient
>>>>>>>>>>>>>> object
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Or maybe we do something like this:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>>>>>>> transDoc.save();
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Florian
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> In Nuxeo the OpenCMIS client API is made available locally as
>>>>>>>>>>>>>>> another
>>>>>>>>>>>>>>> API to manipulate documents, in addition to the Nuxeo native
>>>>>>>>>>>>>>> APIs.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> I have a problem with removing CmisObject.updateProperties()
>>>>>>>>>>>>>>> and
>>>>>>>>>>>>>>> the
>>>>>>>>>>>>>>> mini transient space because for me it's quite useful. The
>>>>>>>>>>>>>>> Nuxeo
>>>>>>>>>>>>>>> internal non-CMIS session has a notion of a property-only
>>>>>>>>>>>>>>> transient
>>>>>>>>>>>>>>> space, so in Nuxeo you update several properties and do some
>>>>>>>>>>>>>>> kind of
>>>>>>>>>>>>>>> object save() to flush them. Without a similar flushing
>>>>>>>>>>>>>>> concept
>>>>>>>>>>>>>>> on the
>>>>>>>>>>>>>>> OpenCMIS client API, I'm obliged to make a flush on every
>>>>>>>>>>>>>>> property
>>>>>>>>>>>>>>> write, which leads to severely degraded performance.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> If all method calls on a CmisObject immediately write
>>>>>>>>>>>>>>> everything
>>>>>>>>>>>>>>> through the network and potentially refetch a full object
>>>>>>>>>>>>>>> there
>>>>>>>>>>>>>>> will
>>>>>>>>>>>>>>> be many people that aren't happy with CMIS performance once
>>>>>>>>>>>>>>> they
>>>>>>>>>>>>>>> get
>>>>>>>>>>>>>>> to use OpenCMIS. The client API is supposed to provide some
>>>>>>>>>>>>>>> convenience to the user, and having a mini transient space for
>>>>>>>>>>>>>>> properties is IMHO the very first step of convenience. There
>>>>>>>>>>>>>>> may
>>>>>>>>>>>>>>> be
>>>>>>>>>>>>>>> problems with the semantics of interactions between this
>>>>>>>>>>>>>>> transient
>>>>>>>>>>>>>>> space and caching / refetches, but let's solve them rather
>>>>>>>>>>>>>>> than
>>>>>>>>>>>>>>> remove
>>>>>>>>>>>>>>> them.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Dave wrote:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> For example, with a transient space, what is the behaviour
>>>>>>>>>>>>>>>> when
>>>>>>>>>>>>>>>> setProperty has been called and an "update" method is then
>>>>>>>>>>>>>>>> called prior
>>>>>>>>>>>>>>>> to
>>>>>>>>>>>>>>>> updateProperties. Are the transient changes discarded,
>>>>>>>>>>>>>>>> flushed,
>>>>>>>>>>>>>>>> or just
>>>>>>>>>>>>>>>> left
>>>>>>>>>>>>>>>> as is?
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> So if I understand correctly you're talking about the case:
>>>>>>>>>>>>>>> 1. doc.setPropertyValue("foo", ...);
>>>>>>>>>>>>>>> 2. doc.updateProperties(map);
>>>>>>>>>>>>>>> 3. doc.setPropertyValue("bar", ...);
>>>>>>>>>>>>>>> 4. doc.updateProperties();
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> And you're asking if the "foo" change is sent with 2. or with
>>>>>>>>>>>>>>> 4.
>>>>>>>>>>>>>>> or
>>>>>>>>>>>>>>> discarded? I'd say let's keep this undefined, as I feel that
>>>>>>>>>>>>>>> it's a
>>>>>>>>>>>>>>> use pattern that's not natural. If we really want to specify
>>>>>>>>>>>>>>> this then
>>>>>>>>>>>>>>> I have no problem mandating that the "foo" change should be
>>>>>>>>>>>>>>> sent
>>>>>>>>>>>>>>> with
>>>>>>>>>>>>>>> 2. by saying that updateProperties(map) is the same as
>>>>>>>>>>>>>>> setPropertyValue() on all the properties of the map then
>>>>>>>>>>>>>>> calling
>>>>>>>>>>>>>>> updateProperties() with the transient map.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Florent
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>>>>>>>>>>>>> <st...@sap.com>               wrote:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Coming back to the cache discussion. I would like to support
>>>>>>>>>>>>>>>> this
>>>>>>>>>>>>>>>> proposal by Dave/Florian and think we can also delete Methods
>>>>>>>>>>>>>>>> on
>>>>>>>>>>>>>>>> Session
>>>>>>>>>>>>>>>> class like cancel() and save() which are currently not
>>>>>>>>>>>>>>>> implemented.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +1 for this:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> - All write operations provided by CmisObject should
>>>>>>>>>>>>>>>>> automatically do
>>>>>>>>>>>>>>>>> an
>>>>>>>>>>>>>>>>> object
>>>>>>>>>>>>>>>>> refresh after the update. That guarantees that the object is
>>>>>>>>>>>>>>>>> always
>>>>>>>>>>>>>>>>> consistent.
>>>>>>>>>>>>>>>>> The cost for this consistency is an additional call to the
>>>>>>>>>>>>>>>>> repository.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> - Is some cases you don't need or want this addition cost.
>>>>>>>>>>>>>>>>> Lets say
>>>>>>>>>>>>>>>>> you
>>>>>>>>>>>>>>>>> just
>>>>>>>>>>>>>>>>> want to update a bunch of objects but you don't work with
>>>>>>>>>>>>>>>>> them
>>>>>>>>>>>>>>>>> afterwards.
>>>>>>>>>>>>>>>>> That's what the operations provided by Session are good for.
>>>>>>>>>>>>>>>>> They just
>>>>>>>>>>>>>>>>> do
>>>>>>>>>>>>>>>>> that and nothing else.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> About the transient support we can design this as an optional
>>>>>>>>>>>>>>>> add on
>>>>>>>>>>>>>>>> with
>>>>>>>>>>>>>>>> additional interfaces and additional implementations. With a
>>>>>>>>>>>>>>>> clear
>>>>>>>>>>>>>>>> separation the API become easier to use.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Regards,
>>>>>>>>>>>>>>>> Stephan
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>>
>>
>>
>
>
>


Re: Proposal to clarify CmisObject caching behaviour

Posted by Florent Guillaume <fg...@nuxeo.com>.
Could you do it in a branch for a few days?
I have a fix to do for the AtomPub bindings (they generate bad atom
alternate links for renditions), and I'll need it for the Nuxeo server
bindings shortly. I'd rather not change the updateProperties / save
that I may be using right now in our connector's code. In a 1-2 days
I'll commit and make a private snapshot and we can merge your branch.
Is that ok?

Florent

On Wed, Nov 10, 2010 at 8:35 PM, Florian Müller
<fl...@alfresco.com> wrote:
> Got it. Thanks.
>
> Would somebody object if I would start the refactoring?
> If we don't like it, we can roll it back.
>
> I would also remove the "persistent" and "transient" notion from the session
> implementation including renaming those classes.
>
>
> - Florian
>
>
>
> On 10/11/2010 17:43, Florent Guillaume wrote:
>>
>> It would be an interface.
>>
>> I agree that it's not obvious in this case that transient behavior can
>> be obtained using an adapter (and autocompletion doc.get... does not
>> immediately provide it). But this can be solved by simple
>> documentation I think. Yes if we think transient documents are
>> fundamental we can make createTransientDocument a synonym to get this
>> adapter. It's not mandatory though.
>>
>> Florent
>>
>> On Wed, Nov 10, 2010 at 3:16 PM, Florian Müller
>> <fl...@alfresco.com>  wrote:
>>>
>>> Hi Florent,
>>>
>>> Could you elaborate a bit more on that proposal?
>>> Would TransientDocument.class be an Interface or a Class?
>>>
>>> I like the idea of adapters. But it is not intuitive that there is an
>>> adapter the provides a transient paradigm. Would it make sense to add
>>> another method that provides a shortcut to the "transient adapter"?
>>>
>>>
>>> Thanks,
>>>
>>> Florian
>>>
>>>
>>> On 10/11/2010 13:27, Florent Guillaume wrote:
>>>>
>>>> I've come around to agreeing that 2. is probably better.
>>>>
>>>> I can see either:
>>>>   TransientDocument transDoc = doc.createTransientDocument():
>>>> or
>>>>   TransientDocument transDoc = doc.getAdapter(TransientDocument.class);
>>>>
>>>> The latter is more extensible for other uses besides transience
>>>> (protocol extensions, application-specific adapters).
>>>>
>>>> WDYT?
>>>>
>>>> Florent
>>>>
>>>>
>>>> On Wed, Nov 10, 2010 at 10:41 AM, Florian Müller
>>>> <fl...@alfresco.com>    wrote:
>>>>>
>>>>> I would like to see that sorted out soon. There are more and more users
>>>>> of OpenCMIS and API changes are usually painful for them. We should
>>>>> also
>>>>> consider a new release (0.2.0) when this is done.
>>>>>
>>>>> So, where are we?
>>>>>
>>>>> The main question is where we want to handle transient data. We have
>>>>> two
>>>>> opinions:
>>>>> 1. Transient and non-transient data access should be covered by the
>>>>> CmisObject interface. (Florent)
>>>>> 2. Transient data access should be covered by a new interface and
>>>>> non-transient data access should be covered by the CmisObject
>>>>> interface.
>>>>> (Florian)
>>>>>
>>>>> Personally, I still want to go for option 2 since it provides cleaner
>>>>> semantics -- especially in multi-threaded environments.
>>>>>
>>>>> Other opinions?
>>>>>
>>>>>
>>>>> - Florian
>>>>>
>>>>>
>>>>> On 08/11/2010 11:51, David Caruana wrote:
>>>>>>
>>>>>> Have we reached a conclusion on this issue? It's been a while since we
>>>>>> last discussed.
>>>>>>
>>>>>> Regards,
>>>>>> Dave
>>>>>>
>>>>>> On 22 Oct 2010, at 15:06, Florian Müller wrote:
>>>>>>
>>>>>>> Oh, right, there is yet another option. :)
>>>>>>>
>>>>>>> I support all your arguments against b), c) and d). But there are
>>>>>>> also
>>>>>>> two issues with e).
>>>>>>> 1. Which value wins if a property is changed in the transient object
>>>>>>> _and_ present in the map?
>>>>>>> 2. save() stores the whole object. If we make ACLs and Policies
>>>>>>> transient too (do we want that?) than updateProperties() has the side
>>>>>>> effect
>>>>>>> of storing those as well.
>>>>>>>
>>>>>>> Which leaves us with a) which is pretty strong. And in this case I
>>>>>>> prefer two interfaces because it much is easier to understand and
>>>>>>> provides
>>>>>>> more compile checks and less runtime surprises.
>>>>>>>
>>>>>>>
>>>>>>> - Florian
>>>>>>>
>>>>>>>
>>>>>>> On 22/10/2010 14:44, Florent Guillaume wrote:
>>>>>>>>
>>>>>>>> On Fri, Oct 22, 2010 at 3:33 PM, Florian Müller
>>>>>>>> <fl...@alfresco.com>       wrote:
>>>>>>>>>
>>>>>>>>> So your proposal is to add a method getTransientObject() (or
>>>>>>>>> something like that) to CmisObject. And that method would return a
>>>>>>>>> transient, not thread-safe version of the object but with
>>>>>>>>> setProperty(),
>>>>>>>>> save(), etc. enabled?
>>>>>>>>> Is that correct?
>>>>>>>>
>>>>>>>> Yes.
>>>>>>>>
>>>>>>>>> In this case we should also add a method isTransient() to
>>>>>>>>> CmisObject.
>>>>>>>>> There should be a way to discover the state of the CmisObject.
>>>>>>>>
>>>>>>>> Yes that would be useful.
>>>>>>>>
>>>>>>>>> I suggest that if the object is not transient, the transient
>>>>>>>>> methods
>>>>>>>>> should throw an IllegalStateException.
>>>>>>>>
>>>>>>>> Ok.
>>>>>>>>
>>>>>>>>> I agree that keeping the number of interfaces and classes low helps
>>>>>>>>> to learn and understand an API. But blending two semantics in one
>>>>>>>>> class
>>>>>>>>> could be even more confusing.
>>>>>>>>> For example, what should happen if updateProperties(Map) is called
>>>>>>>>> on
>>>>>>>>> a transient object? There are multiple options:
>>>>>>>>>    a) updateProperties(Map) throws an exception because it only
>>>>>>>>> works
>>>>>>>>> for non-transient objects.
>>>>>>>>>    b) updateProperties(Map) writes instantly to the repository and
>>>>>>>>> the transient object is refreshed.
>>>>>>>>
>>>>>>>> (which btw means that transient changes are lost)
>>>>>>>>>
>>>>>>>>>    c) updateProperties(Map) writes instantly to the repository and
>>>>>>>>> but object keep its (now outdated) state.
>>>>>>>>>    d) The property map is merged with the transient properties and
>>>>>>>>> written when save() is called.
>>>>>>>>
>>>>>>>> And also:
>>>>>>>> e) The property map is merged with the transient properties and then
>>>>>>>> save() is automatically called.
>>>>>>>>
>>>>>>>>> It is not obvious. All semantics would be right and wrong at the
>>>>>>>>> same
>>>>>>>>> time.
>>>>>>>>
>>>>>>>> Agreed, we have to make a choice. But we would make a similar choice
>>>>>>>> when deciding what methods would be available on the
>>>>>>>> TransientDocument
>>>>>>>> interface and what they would do.
>>>>>>>>
>>>>>>>> But anyway my choices in order of preference would be e) then a).
>>>>>>>> I don't like b) because it loses changes.
>>>>>>>> I don't like c) because there's an issue with not keeping the
>>>>>>>> changes
>>>>>>>> in order.
>>>>>>>> I don't like d) because if you didn't do any transient operation it
>>>>>>>> doesn't behave like its non-transient counterpart.
>>>>>>>>
>>>>>>>> Florent
>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On 22/10/2010 13:43, Florent Guillaume wrote:
>>>>>>>>>>
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> Looking back at your example:
>>>>>>>>>>
>>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>>> transDoc.save();
>>>>>>>>>>
>>>>>>>>>> I agree with the need to explicitly getting a transient object if
>>>>>>>>>> you
>>>>>>>>>> need different semantics.
>>>>>>>>>> One thing that will be painful though is having different classes:
>>>>>>>>>> TransientCmisObject, TransientDocument, TransientFolder, etc.
>>>>>>>>>> Couldn't we simply have all the methods available on the
>>>>>>>>>> CmisObject,
>>>>>>>>>> Document, Folder, etc. and make them throw
>>>>>>>>>> UnsupportedOperationException when called on a non-transient
>>>>>>>>>> object?
>>>>>>>>>> This would tremendously help learning about the API and avoid
>>>>>>>>>> juggling
>>>>>>>>>> with many different interfaces for the users.
>>>>>>>>>>
>>>>>>>>>> Florent
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
>>>>>>>>>> <fl...@alfresco.com>         wrote:
>>>>>>>>>>>
>>>>>>>>>>> Hi Florent,
>>>>>>>>>>>
>>>>>>>>>>> Well, no, there would be no CmisObject.save() method. The save()
>>>>>>>>>>> method
>>>>>>>>>>> would only be on the transient object.
>>>>>>>>>>>
>>>>>>>>>>> CmisObject would have updateProperties(Map), applyAcl(List<Ace>,
>>>>>>>>>>> List<Ace>,
>>>>>>>>>>> AclPropagation), applyPolicy(ObjectId), etc. And all of them
>>>>>>>>>>> would
>>>>>>>>>>> write
>>>>>>>>>>> instantly to the repository and refresh the object.
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Florian
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On 18/10/2010 17:49, Florent Guillaume wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> Ok understood and agreed. There would be a new CmisObject.save()
>>>>>>>>>>>> to
>>>>>>>>>>>> replace updateProperties() then? That works for me as it's a
>>>>>>>>>>>> less
>>>>>>>>>>>> restrictive name that allows for different implementations of
>>>>>>>>>>>> the
>>>>>>>>>>>> transient space that don't deal with just properties.
>>>>>>>>>>>>
>>>>>>>>>>>> Regarding your examples I don't need to do all that, because in
>>>>>>>>>>>> the
>>>>>>>>>>>> Nuxeo use cases I described the client Session I'm providing to
>>>>>>>>>>>> the
>>>>>>>>>>>> user of the API is not a PersistentSessionImpl but a completely
>>>>>>>>>>>> new
>>>>>>>>>>>> Nuxeo class that does all the wrapping it needs around native
>>>>>>>>>>>> Nuxeo
>>>>>>>>>>>> objects. So I'm not constrained by the semantics of the current
>>>>>>>>>>>> PersistentSessionImpl. It's just that I need a save()-like API
>>>>>>>>>>>> to
>>>>>>>>>>>> exist on the CmisObject. And of course I want to have semantics
>>>>>>>>>>>> that
>>>>>>>>>>>> are not too far to what's available when you use an actual
>>>>>>>>>>>> remote
>>>>>>>>>>>> connection using pure OpenCMIS PersistentSessionImpl.
>>>>>>>>>>>>
>>>>>>>>>>>> Florent
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>>>>>>>>>>>> <fl...@alfresco.com>           wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> Hi Florent,
>>>>>>>>>>>>>
>>>>>>>>>>>>> We don't want to remove the transient space entirely. The
>>>>>>>>>>>>> proposal is to
>>>>>>>>>>>>> detach the transient from the non-transient part. We would have
>>>>>>>>>>>>> two
>>>>>>>>>>>>> separate
>>>>>>>>>>>>> objects.
>>>>>>>>>>>>>
>>>>>>>>>>>>> The non-transient object is always consistent, can be shared
>>>>>>>>>>>>> across
>>>>>>>>>>>>> threads
>>>>>>>>>>>>> and is cached. Changes are directly written to the repository.
>>>>>>>>>>>>> This
>>>>>>>>>>>>> object
>>>>>>>>>>>>> would have an updateProperties(Map) method that immediately
>>>>>>>>>>>>> refreshes the
>>>>>>>>>>>>> object after the update.
>>>>>>>>>>>>>
>>>>>>>>>>>>> The transient object is owned by one thread and not thread
>>>>>>>>>>>>> safe.
>>>>>>>>>>>>> That
>>>>>>>>>>>>> should
>>>>>>>>>>>>> prevent inconsistent views on the object. This object would
>>>>>>>>>>>>> have
>>>>>>>>>>>>> setProperty() and save() methods. Internally it would use the
>>>>>>>>>>>>> non-transient
>>>>>>>>>>>>> object to access all unchanged data. It's a wrapper around the
>>>>>>>>>>>>> non-transient
>>>>>>>>>>>>> object that holds the transient data.
>>>>>>>>>>>>>
>>>>>>>>>>>>> So you still could use the pattern that you are using today.
>>>>>>>>>>>>> The
>>>>>>>>>>>>> only
>>>>>>>>>>>>> difference would be that you have to create a transient wrapper
>>>>>>>>>>>>> object.
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> That could look like this:
>>>>>>>>>>>>>
>>>>>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>>>>>> TransientDocument transDoc = new TransientDocument(doc);
>>>>>>>>>>>>>
>>>>>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>>>>>> transDoc.save(); // that also refreshes the underlying
>>>>>>>>>>>>> non-transient
>>>>>>>>>>>>> object
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> Or maybe we do something like this:
>>>>>>>>>>>>>
>>>>>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>>>>>>>>
>>>>>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>>>>>> transDoc.save();
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> Florian
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> In Nuxeo the OpenCMIS client API is made available locally as
>>>>>>>>>>>>>> another
>>>>>>>>>>>>>> API to manipulate documents, in addition to the Nuxeo native
>>>>>>>>>>>>>> APIs.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I have a problem with removing CmisObject.updateProperties()
>>>>>>>>>>>>>> and
>>>>>>>>>>>>>> the
>>>>>>>>>>>>>> mini transient space because for me it's quite useful. The
>>>>>>>>>>>>>> Nuxeo
>>>>>>>>>>>>>> internal non-CMIS session has a notion of a property-only
>>>>>>>>>>>>>> transient
>>>>>>>>>>>>>> space, so in Nuxeo you update several properties and do some
>>>>>>>>>>>>>> kind of
>>>>>>>>>>>>>> object save() to flush them. Without a similar flushing
>>>>>>>>>>>>>> concept
>>>>>>>>>>>>>> on the
>>>>>>>>>>>>>> OpenCMIS client API, I'm obliged to make a flush on every
>>>>>>>>>>>>>> property
>>>>>>>>>>>>>> write, which leads to severely degraded performance.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> If all method calls on a CmisObject immediately write
>>>>>>>>>>>>>> everything
>>>>>>>>>>>>>> through the network and potentially refetch a full object
>>>>>>>>>>>>>> there
>>>>>>>>>>>>>> will
>>>>>>>>>>>>>> be many people that aren't happy with CMIS performance once
>>>>>>>>>>>>>> they
>>>>>>>>>>>>>> get
>>>>>>>>>>>>>> to use OpenCMIS. The client API is supposed to provide some
>>>>>>>>>>>>>> convenience to the user, and having a mini transient space for
>>>>>>>>>>>>>> properties is IMHO the very first step of convenience. There
>>>>>>>>>>>>>> may
>>>>>>>>>>>>>> be
>>>>>>>>>>>>>> problems with the semantics of interactions between this
>>>>>>>>>>>>>> transient
>>>>>>>>>>>>>> space and caching / refetches, but let's solve them rather
>>>>>>>>>>>>>> than
>>>>>>>>>>>>>> remove
>>>>>>>>>>>>>> them.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Dave wrote:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> For example, with a transient space, what is the behaviour
>>>>>>>>>>>>>>> when
>>>>>>>>>>>>>>> setProperty has been called and an "update" method is then
>>>>>>>>>>>>>>> called prior
>>>>>>>>>>>>>>> to
>>>>>>>>>>>>>>> updateProperties. Are the transient changes discarded,
>>>>>>>>>>>>>>> flushed,
>>>>>>>>>>>>>>> or just
>>>>>>>>>>>>>>> left
>>>>>>>>>>>>>>> as is?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> So if I understand correctly you're talking about the case:
>>>>>>>>>>>>>> 1. doc.setPropertyValue("foo", ...);
>>>>>>>>>>>>>> 2. doc.updateProperties(map);
>>>>>>>>>>>>>> 3. doc.setPropertyValue("bar", ...);
>>>>>>>>>>>>>> 4. doc.updateProperties();
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> And you're asking if the "foo" change is sent with 2. or with
>>>>>>>>>>>>>> 4.
>>>>>>>>>>>>>> or
>>>>>>>>>>>>>> discarded? I'd say let's keep this undefined, as I feel that
>>>>>>>>>>>>>> it's a
>>>>>>>>>>>>>> use pattern that's not natural. If we really want to specify
>>>>>>>>>>>>>> this then
>>>>>>>>>>>>>> I have no problem mandating that the "foo" change should be
>>>>>>>>>>>>>> sent
>>>>>>>>>>>>>> with
>>>>>>>>>>>>>> 2. by saying that updateProperties(map) is the same as
>>>>>>>>>>>>>> setPropertyValue() on all the properties of the map then
>>>>>>>>>>>>>> calling
>>>>>>>>>>>>>> updateProperties() with the transient map.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Florent
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>>>>>>>>>>>> <st...@sap.com>             wrote:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Coming back to the cache discussion. I would like to support
>>>>>>>>>>>>>>> this
>>>>>>>>>>>>>>> proposal by Dave/Florian and think we can also delete Methods
>>>>>>>>>>>>>>> on
>>>>>>>>>>>>>>> Session
>>>>>>>>>>>>>>> class like cancel() and save() which are currently not
>>>>>>>>>>>>>>> implemented.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +1 for this:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> - All write operations provided by CmisObject should
>>>>>>>>>>>>>>>> automatically do
>>>>>>>>>>>>>>>> an
>>>>>>>>>>>>>>>> object
>>>>>>>>>>>>>>>> refresh after the update. That guarantees that the object is
>>>>>>>>>>>>>>>> always
>>>>>>>>>>>>>>>> consistent.
>>>>>>>>>>>>>>>> The cost for this consistency is an additional call to the
>>>>>>>>>>>>>>>> repository.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> - Is some cases you don't need or want this addition cost.
>>>>>>>>>>>>>>>> Lets say
>>>>>>>>>>>>>>>> you
>>>>>>>>>>>>>>>> just
>>>>>>>>>>>>>>>> want to update a bunch of objects but you don't work with
>>>>>>>>>>>>>>>> them
>>>>>>>>>>>>>>>> afterwards.
>>>>>>>>>>>>>>>> That's what the operations provided by Session are good for.
>>>>>>>>>>>>>>>> They just
>>>>>>>>>>>>>>>> do
>>>>>>>>>>>>>>>> that and nothing else.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> About the transient support we can design this as an optional
>>>>>>>>>>>>>>> add on
>>>>>>>>>>>>>>> with
>>>>>>>>>>>>>>> additional interfaces and additional implementations. With a
>>>>>>>>>>>>>>> clear
>>>>>>>>>>>>>>> separation the API become easier to use.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Regards,
>>>>>>>>>>>>>>> Stephan
>>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>>
>
>



-- 
Florent Guillaume, Director of R&D, Nuxeo
Open Source, Java EE based, Enterprise Content Management (ECM)
http://www.nuxeo.com   http://www.nuxeo.org   +33 1 40 33 79 87

Re: Proposal to clarify CmisObject caching behaviour

Posted by Florian Müller <fl...@alfresco.com>.
Got it. Thanks.

Would somebody object if I would start the refactoring?
If we don't like it, we can roll it back.

I would also remove the "persistent" and "transient" notion from the 
session implementation including renaming those classes.


- Florian



On 10/11/2010 17:43, Florent Guillaume wrote:
> It would be an interface.
>
> I agree that it's not obvious in this case that transient behavior can
> be obtained using an adapter (and autocompletion doc.get... does not
> immediately provide it). But this can be solved by simple
> documentation I think. Yes if we think transient documents are
> fundamental we can make createTransientDocument a synonym to get this
> adapter. It's not mandatory though.
>
> Florent
>
> On Wed, Nov 10, 2010 at 3:16 PM, Florian Müller
> <fl...@alfresco.com>  wrote:
>> Hi Florent,
>>
>> Could you elaborate a bit more on that proposal?
>> Would TransientDocument.class be an Interface or a Class?
>>
>> I like the idea of adapters. But it is not intuitive that there is an
>> adapter the provides a transient paradigm. Would it make sense to add
>> another method that provides a shortcut to the "transient adapter"?
>>
>>
>> Thanks,
>>
>> Florian
>>
>>
>> On 10/11/2010 13:27, Florent Guillaume wrote:
>>>
>>> I've come around to agreeing that 2. is probably better.
>>>
>>> I can see either:
>>>    TransientDocument transDoc = doc.createTransientDocument():
>>> or
>>>    TransientDocument transDoc = doc.getAdapter(TransientDocument.class);
>>>
>>> The latter is more extensible for other uses besides transience
>>> (protocol extensions, application-specific adapters).
>>>
>>> WDYT?
>>>
>>> Florent
>>>
>>>
>>> On Wed, Nov 10, 2010 at 10:41 AM, Florian Müller
>>> <fl...@alfresco.com>    wrote:
>>>>
>>>> I would like to see that sorted out soon. There are more and more users
>>>> of OpenCMIS and API changes are usually painful for them. We should also
>>>> consider a new release (0.2.0) when this is done.
>>>>
>>>> So, where are we?
>>>>
>>>> The main question is where we want to handle transient data. We have two
>>>> opinions:
>>>> 1. Transient and non-transient data access should be covered by the
>>>> CmisObject interface. (Florent)
>>>> 2. Transient data access should be covered by a new interface and
>>>> non-transient data access should be covered by the CmisObject interface.
>>>> (Florian)
>>>>
>>>> Personally, I still want to go for option 2 since it provides cleaner
>>>> semantics -- especially in multi-threaded environments.
>>>>
>>>> Other opinions?
>>>>
>>>>
>>>> - Florian
>>>>
>>>>
>>>> On 08/11/2010 11:51, David Caruana wrote:
>>>>>
>>>>> Have we reached a conclusion on this issue? It's been a while since we
>>>>> last discussed.
>>>>>
>>>>> Regards,
>>>>> Dave
>>>>>
>>>>> On 22 Oct 2010, at 15:06, Florian Müller wrote:
>>>>>
>>>>>> Oh, right, there is yet another option. :)
>>>>>>
>>>>>> I support all your arguments against b), c) and d). But there are also
>>>>>> two issues with e).
>>>>>> 1. Which value wins if a property is changed in the transient object
>>>>>> _and_ present in the map?
>>>>>> 2. save() stores the whole object. If we make ACLs and Policies
>>>>>> transient too (do we want that?) than updateProperties() has the side effect
>>>>>> of storing those as well.
>>>>>>
>>>>>> Which leaves us with a) which is pretty strong. And in this case I
>>>>>> prefer two interfaces because it much is easier to understand and provides
>>>>>> more compile checks and less runtime surprises.
>>>>>>
>>>>>>
>>>>>> - Florian
>>>>>>
>>>>>>
>>>>>> On 22/10/2010 14:44, Florent Guillaume wrote:
>>>>>>>
>>>>>>> On Fri, Oct 22, 2010 at 3:33 PM, Florian Müller
>>>>>>> <fl...@alfresco.com>       wrote:
>>>>>>>>
>>>>>>>> So your proposal is to add a method getTransientObject() (or
>>>>>>>> something like that) to CmisObject. And that method would return a
>>>>>>>> transient, not thread-safe version of the object but with setProperty(),
>>>>>>>> save(), etc. enabled?
>>>>>>>> Is that correct?
>>>>>>>
>>>>>>> Yes.
>>>>>>>
>>>>>>>> In this case we should also add a method isTransient() to CmisObject.
>>>>>>>> There should be a way to discover the state of the CmisObject.
>>>>>>>
>>>>>>> Yes that would be useful.
>>>>>>>
>>>>>>>> I suggest that if the object is not transient, the transient methods
>>>>>>>> should throw an IllegalStateException.
>>>>>>>
>>>>>>> Ok.
>>>>>>>
>>>>>>>> I agree that keeping the number of interfaces and classes low helps
>>>>>>>> to learn and understand an API. But blending two semantics in one class
>>>>>>>> could be even more confusing.
>>>>>>>> For example, what should happen if updateProperties(Map) is called on
>>>>>>>> a transient object? There are multiple options:
>>>>>>>>     a) updateProperties(Map) throws an exception because it only works
>>>>>>>> for non-transient objects.
>>>>>>>>     b) updateProperties(Map) writes instantly to the repository and
>>>>>>>> the transient object is refreshed.
>>>>>>>
>>>>>>> (which btw means that transient changes are lost)
>>>>>>>>
>>>>>>>>     c) updateProperties(Map) writes instantly to the repository and
>>>>>>>> but object keep its (now outdated) state.
>>>>>>>>     d) The property map is merged with the transient properties and
>>>>>>>> written when save() is called.
>>>>>>>
>>>>>>> And also:
>>>>>>> e) The property map is merged with the transient properties and then
>>>>>>> save() is automatically called.
>>>>>>>
>>>>>>>> It is not obvious. All semantics would be right and wrong at the same
>>>>>>>> time.
>>>>>>>
>>>>>>> Agreed, we have to make a choice. But we would make a similar choice
>>>>>>> when deciding what methods would be available on the TransientDocument
>>>>>>> interface and what they would do.
>>>>>>>
>>>>>>> But anyway my choices in order of preference would be e) then a).
>>>>>>> I don't like b) because it loses changes.
>>>>>>> I don't like c) because there's an issue with not keeping the changes
>>>>>>> in order.
>>>>>>> I don't like d) because if you didn't do any transient operation it
>>>>>>> doesn't behave like its non-transient counterpart.
>>>>>>>
>>>>>>> Florent
>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On 22/10/2010 13:43, Florent Guillaume wrote:
>>>>>>>>>
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> Looking back at your example:
>>>>>>>>>
>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>> transDoc.save();
>>>>>>>>>
>>>>>>>>> I agree with the need to explicitly getting a transient object if
>>>>>>>>> you
>>>>>>>>> need different semantics.
>>>>>>>>> One thing that will be painful though is having different classes:
>>>>>>>>> TransientCmisObject, TransientDocument, TransientFolder, etc.
>>>>>>>>> Couldn't we simply have all the methods available on the CmisObject,
>>>>>>>>> Document, Folder, etc. and make them throw
>>>>>>>>> UnsupportedOperationException when called on a non-transient object?
>>>>>>>>> This would tremendously help learning about the API and avoid
>>>>>>>>> juggling
>>>>>>>>> with many different interfaces for the users.
>>>>>>>>>
>>>>>>>>> Florent
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
>>>>>>>>> <fl...@alfresco.com>         wrote:
>>>>>>>>>>
>>>>>>>>>> Hi Florent,
>>>>>>>>>>
>>>>>>>>>> Well, no, there would be no CmisObject.save() method. The save()
>>>>>>>>>> method
>>>>>>>>>> would only be on the transient object.
>>>>>>>>>>
>>>>>>>>>> CmisObject would have updateProperties(Map), applyAcl(List<Ace>,
>>>>>>>>>> List<Ace>,
>>>>>>>>>> AclPropagation), applyPolicy(ObjectId), etc. And all of them would
>>>>>>>>>> write
>>>>>>>>>> instantly to the repository and refresh the object.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Florian
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On 18/10/2010 17:49, Florent Guillaume wrote:
>>>>>>>>>>>
>>>>>>>>>>> Ok understood and agreed. There would be a new CmisObject.save()
>>>>>>>>>>> to
>>>>>>>>>>> replace updateProperties() then? That works for me as it's a less
>>>>>>>>>>> restrictive name that allows for different implementations of the
>>>>>>>>>>> transient space that don't deal with just properties.
>>>>>>>>>>>
>>>>>>>>>>> Regarding your examples I don't need to do all that, because in
>>>>>>>>>>> the
>>>>>>>>>>> Nuxeo use cases I described the client Session I'm providing to
>>>>>>>>>>> the
>>>>>>>>>>> user of the API is not a PersistentSessionImpl but a completely
>>>>>>>>>>> new
>>>>>>>>>>> Nuxeo class that does all the wrapping it needs around native
>>>>>>>>>>> Nuxeo
>>>>>>>>>>> objects. So I'm not constrained by the semantics of the current
>>>>>>>>>>> PersistentSessionImpl. It's just that I need a save()-like API to
>>>>>>>>>>> exist on the CmisObject. And of course I want to have semantics
>>>>>>>>>>> that
>>>>>>>>>>> are not too far to what's available when you use an actual remote
>>>>>>>>>>> connection using pure OpenCMIS PersistentSessionImpl.
>>>>>>>>>>>
>>>>>>>>>>> Florent
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>>>>>>>>>>> <fl...@alfresco.com>           wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> Hi Florent,
>>>>>>>>>>>>
>>>>>>>>>>>> We don't want to remove the transient space entirely. The
>>>>>>>>>>>> proposal is to
>>>>>>>>>>>> detach the transient from the non-transient part. We would have
>>>>>>>>>>>> two
>>>>>>>>>>>> separate
>>>>>>>>>>>> objects.
>>>>>>>>>>>>
>>>>>>>>>>>> The non-transient object is always consistent, can be shared
>>>>>>>>>>>> across
>>>>>>>>>>>> threads
>>>>>>>>>>>> and is cached. Changes are directly written to the repository.
>>>>>>>>>>>> This
>>>>>>>>>>>> object
>>>>>>>>>>>> would have an updateProperties(Map) method that immediately
>>>>>>>>>>>> refreshes the
>>>>>>>>>>>> object after the update.
>>>>>>>>>>>>
>>>>>>>>>>>> The transient object is owned by one thread and not thread safe.
>>>>>>>>>>>> That
>>>>>>>>>>>> should
>>>>>>>>>>>> prevent inconsistent views on the object. This object would have
>>>>>>>>>>>> setProperty() and save() methods. Internally it would use the
>>>>>>>>>>>> non-transient
>>>>>>>>>>>> object to access all unchanged data. It's a wrapper around the
>>>>>>>>>>>> non-transient
>>>>>>>>>>>> object that holds the transient data.
>>>>>>>>>>>>
>>>>>>>>>>>> So you still could use the pattern that you are using today. The
>>>>>>>>>>>> only
>>>>>>>>>>>> difference would be that you have to create a transient wrapper
>>>>>>>>>>>> object.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> That could look like this:
>>>>>>>>>>>>
>>>>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>>>>> TransientDocument transDoc = new TransientDocument(doc);
>>>>>>>>>>>>
>>>>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>>>>> transDoc.save(); // that also refreshes the underlying
>>>>>>>>>>>> non-transient
>>>>>>>>>>>> object
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Or maybe we do something like this:
>>>>>>>>>>>>
>>>>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>>>>>>>
>>>>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>>>>> transDoc.save();
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Florian
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>
>>>>>>>>>>>>> In Nuxeo the OpenCMIS client API is made available locally as
>>>>>>>>>>>>> another
>>>>>>>>>>>>> API to manipulate documents, in addition to the Nuxeo native
>>>>>>>>>>>>> APIs.
>>>>>>>>>>>>>
>>>>>>>>>>>>> I have a problem with removing CmisObject.updateProperties() and
>>>>>>>>>>>>> the
>>>>>>>>>>>>> mini transient space because for me it's quite useful. The Nuxeo
>>>>>>>>>>>>> internal non-CMIS session has a notion of a property-only
>>>>>>>>>>>>> transient
>>>>>>>>>>>>> space, so in Nuxeo you update several properties and do some
>>>>>>>>>>>>> kind of
>>>>>>>>>>>>> object save() to flush them. Without a similar flushing concept
>>>>>>>>>>>>> on the
>>>>>>>>>>>>> OpenCMIS client API, I'm obliged to make a flush on every
>>>>>>>>>>>>> property
>>>>>>>>>>>>> write, which leads to severely degraded performance.
>>>>>>>>>>>>>
>>>>>>>>>>>>> If all method calls on a CmisObject immediately write everything
>>>>>>>>>>>>> through the network and potentially refetch a full object there
>>>>>>>>>>>>> will
>>>>>>>>>>>>> be many people that aren't happy with CMIS performance once they
>>>>>>>>>>>>> get
>>>>>>>>>>>>> to use OpenCMIS. The client API is supposed to provide some
>>>>>>>>>>>>> convenience to the user, and having a mini transient space for
>>>>>>>>>>>>> properties is IMHO the very first step of convenience. There may
>>>>>>>>>>>>> be
>>>>>>>>>>>>> problems with the semantics of interactions between this
>>>>>>>>>>>>> transient
>>>>>>>>>>>>> space and caching / refetches, but let's solve them rather than
>>>>>>>>>>>>> remove
>>>>>>>>>>>>> them.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Dave wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> For example, with a transient space, what is the behaviour when
>>>>>>>>>>>>>> setProperty has been called and an "update" method is then
>>>>>>>>>>>>>> called prior
>>>>>>>>>>>>>> to
>>>>>>>>>>>>>> updateProperties. Are the transient changes discarded, flushed,
>>>>>>>>>>>>>> or just
>>>>>>>>>>>>>> left
>>>>>>>>>>>>>> as is?
>>>>>>>>>>>>>
>>>>>>>>>>>>> So if I understand correctly you're talking about the case:
>>>>>>>>>>>>> 1. doc.setPropertyValue("foo", ...);
>>>>>>>>>>>>> 2. doc.updateProperties(map);
>>>>>>>>>>>>> 3. doc.setPropertyValue("bar", ...);
>>>>>>>>>>>>> 4. doc.updateProperties();
>>>>>>>>>>>>>
>>>>>>>>>>>>> And you're asking if the "foo" change is sent with 2. or with 4.
>>>>>>>>>>>>> or
>>>>>>>>>>>>> discarded? I'd say let's keep this undefined, as I feel that
>>>>>>>>>>>>> it's a
>>>>>>>>>>>>> use pattern that's not natural. If we really want to specify
>>>>>>>>>>>>> this then
>>>>>>>>>>>>> I have no problem mandating that the "foo" change should be sent
>>>>>>>>>>>>> with
>>>>>>>>>>>>> 2. by saying that updateProperties(map) is the same as
>>>>>>>>>>>>> setPropertyValue() on all the properties of the map then calling
>>>>>>>>>>>>> updateProperties() with the transient map.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Florent
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>>>>>>>>>>> <st...@sap.com>             wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Coming back to the cache discussion. I would like to support
>>>>>>>>>>>>>> this
>>>>>>>>>>>>>> proposal by Dave/Florian and think we can also delete Methods
>>>>>>>>>>>>>> on
>>>>>>>>>>>>>> Session
>>>>>>>>>>>>>> class like cancel() and save() which are currently not
>>>>>>>>>>>>>> implemented.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +1 for this:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> - All write operations provided by CmisObject should
>>>>>>>>>>>>>>> automatically do
>>>>>>>>>>>>>>> an
>>>>>>>>>>>>>>> object
>>>>>>>>>>>>>>> refresh after the update. That guarantees that the object is
>>>>>>>>>>>>>>> always
>>>>>>>>>>>>>>> consistent.
>>>>>>>>>>>>>>> The cost for this consistency is an additional call to the
>>>>>>>>>>>>>>> repository.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> - Is some cases you don't need or want this addition cost.
>>>>>>>>>>>>>>> Lets say
>>>>>>>>>>>>>>> you
>>>>>>>>>>>>>>> just
>>>>>>>>>>>>>>> want to update a bunch of objects but you don't work with them
>>>>>>>>>>>>>>> afterwards.
>>>>>>>>>>>>>>> That's what the operations provided by Session are good for.
>>>>>>>>>>>>>>> They just
>>>>>>>>>>>>>>> do
>>>>>>>>>>>>>>> that and nothing else.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> About the transient support we can design this as an optional
>>>>>>>>>>>>>> add on
>>>>>>>>>>>>>> with
>>>>>>>>>>>>>> additional interfaces and additional implementations. With a
>>>>>>>>>>>>>> clear
>>>>>>>>>>>>>> separation the API become easier to use.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Regards,
>>>>>>>>>>>>>> Stephan
>>>>
>>>
>>>
>>>
>>
>>
>
>
>


Re: Proposal to clarify CmisObject caching behaviour

Posted by Florent Guillaume <fg...@nuxeo.com>.
It would be an interface.

I agree that it's not obvious in this case that transient behavior can
be obtained using an adapter (and autocompletion doc.get... does not
immediately provide it). But this can be solved by simple
documentation I think. Yes if we think transient documents are
fundamental we can make createTransientDocument a synonym to get this
adapter. It's not mandatory though.

Florent

On Wed, Nov 10, 2010 at 3:16 PM, Florian Müller
<fl...@alfresco.com> wrote:
> Hi Florent,
>
> Could you elaborate a bit more on that proposal?
> Would TransientDocument.class be an Interface or a Class?
>
> I like the idea of adapters. But it is not intuitive that there is an
> adapter the provides a transient paradigm. Would it make sense to add
> another method that provides a shortcut to the "transient adapter"?
>
>
> Thanks,
>
> Florian
>
>
> On 10/11/2010 13:27, Florent Guillaume wrote:
>>
>> I've come around to agreeing that 2. is probably better.
>>
>> I can see either:
>>   TransientDocument transDoc = doc.createTransientDocument():
>> or
>>   TransientDocument transDoc = doc.getAdapter(TransientDocument.class);
>>
>> The latter is more extensible for other uses besides transience
>> (protocol extensions, application-specific adapters).
>>
>> WDYT?
>>
>> Florent
>>
>>
>> On Wed, Nov 10, 2010 at 10:41 AM, Florian Müller
>> <fl...@alfresco.com>  wrote:
>>>
>>> I would like to see that sorted out soon. There are more and more users
>>> of OpenCMIS and API changes are usually painful for them. We should also
>>> consider a new release (0.2.0) when this is done.
>>>
>>> So, where are we?
>>>
>>> The main question is where we want to handle transient data. We have two
>>> opinions:
>>> 1. Transient and non-transient data access should be covered by the
>>> CmisObject interface. (Florent)
>>> 2. Transient data access should be covered by a new interface and
>>> non-transient data access should be covered by the CmisObject interface.
>>> (Florian)
>>>
>>> Personally, I still want to go for option 2 since it provides cleaner
>>> semantics -- especially in multi-threaded environments.
>>>
>>> Other opinions?
>>>
>>>
>>> - Florian
>>>
>>>
>>> On 08/11/2010 11:51, David Caruana wrote:
>>>>
>>>> Have we reached a conclusion on this issue? It's been a while since we
>>>> last discussed.
>>>>
>>>> Regards,
>>>> Dave
>>>>
>>>> On 22 Oct 2010, at 15:06, Florian Müller wrote:
>>>>
>>>>> Oh, right, there is yet another option. :)
>>>>>
>>>>> I support all your arguments against b), c) and d). But there are also
>>>>> two issues with e).
>>>>> 1. Which value wins if a property is changed in the transient object
>>>>> _and_ present in the map?
>>>>> 2. save() stores the whole object. If we make ACLs and Policies
>>>>> transient too (do we want that?) than updateProperties() has the side effect
>>>>> of storing those as well.
>>>>>
>>>>> Which leaves us with a) which is pretty strong. And in this case I
>>>>> prefer two interfaces because it much is easier to understand and provides
>>>>> more compile checks and less runtime surprises.
>>>>>
>>>>>
>>>>> - Florian
>>>>>
>>>>>
>>>>> On 22/10/2010 14:44, Florent Guillaume wrote:
>>>>>>
>>>>>> On Fri, Oct 22, 2010 at 3:33 PM, Florian Müller
>>>>>> <fl...@alfresco.com>     wrote:
>>>>>>>
>>>>>>> So your proposal is to add a method getTransientObject() (or
>>>>>>> something like that) to CmisObject. And that method would return a
>>>>>>> transient, not thread-safe version of the object but with setProperty(),
>>>>>>> save(), etc. enabled?
>>>>>>> Is that correct?
>>>>>>
>>>>>> Yes.
>>>>>>
>>>>>>> In this case we should also add a method isTransient() to CmisObject.
>>>>>>> There should be a way to discover the state of the CmisObject.
>>>>>>
>>>>>> Yes that would be useful.
>>>>>>
>>>>>>> I suggest that if the object is not transient, the transient methods
>>>>>>> should throw an IllegalStateException.
>>>>>>
>>>>>> Ok.
>>>>>>
>>>>>>> I agree that keeping the number of interfaces and classes low helps
>>>>>>> to learn and understand an API. But blending two semantics in one class
>>>>>>> could be even more confusing.
>>>>>>> For example, what should happen if updateProperties(Map) is called on
>>>>>>> a transient object? There are multiple options:
>>>>>>>    a) updateProperties(Map) throws an exception because it only works
>>>>>>> for non-transient objects.
>>>>>>>    b) updateProperties(Map) writes instantly to the repository and
>>>>>>> the transient object is refreshed.
>>>>>>
>>>>>> (which btw means that transient changes are lost)
>>>>>>>
>>>>>>>    c) updateProperties(Map) writes instantly to the repository and
>>>>>>> but object keep its (now outdated) state.
>>>>>>>    d) The property map is merged with the transient properties and
>>>>>>> written when save() is called.
>>>>>>
>>>>>> And also:
>>>>>> e) The property map is merged with the transient properties and then
>>>>>> save() is automatically called.
>>>>>>
>>>>>>> It is not obvious. All semantics would be right and wrong at the same
>>>>>>> time.
>>>>>>
>>>>>> Agreed, we have to make a choice. But we would make a similar choice
>>>>>> when deciding what methods would be available on the TransientDocument
>>>>>> interface and what they would do.
>>>>>>
>>>>>> But anyway my choices in order of preference would be e) then a).
>>>>>> I don't like b) because it loses changes.
>>>>>> I don't like c) because there's an issue with not keeping the changes
>>>>>> in order.
>>>>>> I don't like d) because if you didn't do any transient operation it
>>>>>> doesn't behave like its non-transient counterpart.
>>>>>>
>>>>>> Florent
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On 22/10/2010 13:43, Florent Guillaume wrote:
>>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> Looking back at your example:
>>>>>>>>
>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>> transDoc.save();
>>>>>>>>
>>>>>>>> I agree with the need to explicitly getting a transient object if
>>>>>>>> you
>>>>>>>> need different semantics.
>>>>>>>> One thing that will be painful though is having different classes:
>>>>>>>> TransientCmisObject, TransientDocument, TransientFolder, etc.
>>>>>>>> Couldn't we simply have all the methods available on the CmisObject,
>>>>>>>> Document, Folder, etc. and make them throw
>>>>>>>> UnsupportedOperationException when called on a non-transient object?
>>>>>>>> This would tremendously help learning about the API and avoid
>>>>>>>> juggling
>>>>>>>> with many different interfaces for the users.
>>>>>>>>
>>>>>>>> Florent
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
>>>>>>>> <fl...@alfresco.com>       wrote:
>>>>>>>>>
>>>>>>>>> Hi Florent,
>>>>>>>>>
>>>>>>>>> Well, no, there would be no CmisObject.save() method. The save()
>>>>>>>>> method
>>>>>>>>> would only be on the transient object.
>>>>>>>>>
>>>>>>>>> CmisObject would have updateProperties(Map), applyAcl(List<Ace>,
>>>>>>>>> List<Ace>,
>>>>>>>>> AclPropagation), applyPolicy(ObjectId), etc. And all of them would
>>>>>>>>> write
>>>>>>>>> instantly to the repository and refresh the object.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Florian
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On 18/10/2010 17:49, Florent Guillaume wrote:
>>>>>>>>>>
>>>>>>>>>> Ok understood and agreed. There would be a new CmisObject.save()
>>>>>>>>>> to
>>>>>>>>>> replace updateProperties() then? That works for me as it's a less
>>>>>>>>>> restrictive name that allows for different implementations of the
>>>>>>>>>> transient space that don't deal with just properties.
>>>>>>>>>>
>>>>>>>>>> Regarding your examples I don't need to do all that, because in
>>>>>>>>>> the
>>>>>>>>>> Nuxeo use cases I described the client Session I'm providing to
>>>>>>>>>> the
>>>>>>>>>> user of the API is not a PersistentSessionImpl but a completely
>>>>>>>>>> new
>>>>>>>>>> Nuxeo class that does all the wrapping it needs around native
>>>>>>>>>> Nuxeo
>>>>>>>>>> objects. So I'm not constrained by the semantics of the current
>>>>>>>>>> PersistentSessionImpl. It's just that I need a save()-like API to
>>>>>>>>>> exist on the CmisObject. And of course I want to have semantics
>>>>>>>>>> that
>>>>>>>>>> are not too far to what's available when you use an actual remote
>>>>>>>>>> connection using pure OpenCMIS PersistentSessionImpl.
>>>>>>>>>>
>>>>>>>>>> Florent
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>>>>>>>>>> <fl...@alfresco.com>         wrote:
>>>>>>>>>>>
>>>>>>>>>>> Hi Florent,
>>>>>>>>>>>
>>>>>>>>>>> We don't want to remove the transient space entirely. The
>>>>>>>>>>> proposal is to
>>>>>>>>>>> detach the transient from the non-transient part. We would have
>>>>>>>>>>> two
>>>>>>>>>>> separate
>>>>>>>>>>> objects.
>>>>>>>>>>>
>>>>>>>>>>> The non-transient object is always consistent, can be shared
>>>>>>>>>>> across
>>>>>>>>>>> threads
>>>>>>>>>>> and is cached. Changes are directly written to the repository.
>>>>>>>>>>> This
>>>>>>>>>>> object
>>>>>>>>>>> would have an updateProperties(Map) method that immediately
>>>>>>>>>>> refreshes the
>>>>>>>>>>> object after the update.
>>>>>>>>>>>
>>>>>>>>>>> The transient object is owned by one thread and not thread safe.
>>>>>>>>>>> That
>>>>>>>>>>> should
>>>>>>>>>>> prevent inconsistent views on the object. This object would have
>>>>>>>>>>> setProperty() and save() methods. Internally it would use the
>>>>>>>>>>> non-transient
>>>>>>>>>>> object to access all unchanged data. It's a wrapper around the
>>>>>>>>>>> non-transient
>>>>>>>>>>> object that holds the transient data.
>>>>>>>>>>>
>>>>>>>>>>> So you still could use the pattern that you are using today. The
>>>>>>>>>>> only
>>>>>>>>>>> difference would be that you have to create a transient wrapper
>>>>>>>>>>> object.
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> That could look like this:
>>>>>>>>>>>
>>>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>>>> TransientDocument transDoc = new TransientDocument(doc);
>>>>>>>>>>>
>>>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>>>> transDoc.save(); // that also refreshes the underlying
>>>>>>>>>>> non-transient
>>>>>>>>>>> object
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Or maybe we do something like this:
>>>>>>>>>>>
>>>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>>>>>>
>>>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>>>> transDoc.save();
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Florian
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> Hi,
>>>>>>>>>>>>
>>>>>>>>>>>> In Nuxeo the OpenCMIS client API is made available locally as
>>>>>>>>>>>> another
>>>>>>>>>>>> API to manipulate documents, in addition to the Nuxeo native
>>>>>>>>>>>> APIs.
>>>>>>>>>>>>
>>>>>>>>>>>> I have a problem with removing CmisObject.updateProperties() and
>>>>>>>>>>>> the
>>>>>>>>>>>> mini transient space because for me it's quite useful. The Nuxeo
>>>>>>>>>>>> internal non-CMIS session has a notion of a property-only
>>>>>>>>>>>> transient
>>>>>>>>>>>> space, so in Nuxeo you update several properties and do some
>>>>>>>>>>>> kind of
>>>>>>>>>>>> object save() to flush them. Without a similar flushing concept
>>>>>>>>>>>> on the
>>>>>>>>>>>> OpenCMIS client API, I'm obliged to make a flush on every
>>>>>>>>>>>> property
>>>>>>>>>>>> write, which leads to severely degraded performance.
>>>>>>>>>>>>
>>>>>>>>>>>> If all method calls on a CmisObject immediately write everything
>>>>>>>>>>>> through the network and potentially refetch a full object there
>>>>>>>>>>>> will
>>>>>>>>>>>> be many people that aren't happy with CMIS performance once they
>>>>>>>>>>>> get
>>>>>>>>>>>> to use OpenCMIS. The client API is supposed to provide some
>>>>>>>>>>>> convenience to the user, and having a mini transient space for
>>>>>>>>>>>> properties is IMHO the very first step of convenience. There may
>>>>>>>>>>>> be
>>>>>>>>>>>> problems with the semantics of interactions between this
>>>>>>>>>>>> transient
>>>>>>>>>>>> space and caching / refetches, but let's solve them rather than
>>>>>>>>>>>> remove
>>>>>>>>>>>> them.
>>>>>>>>>>>>
>>>>>>>>>>>> Dave wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> For example, with a transient space, what is the behaviour when
>>>>>>>>>>>>> setProperty has been called and an "update" method is then
>>>>>>>>>>>>> called prior
>>>>>>>>>>>>> to
>>>>>>>>>>>>> updateProperties. Are the transient changes discarded, flushed,
>>>>>>>>>>>>> or just
>>>>>>>>>>>>> left
>>>>>>>>>>>>> as is?
>>>>>>>>>>>>
>>>>>>>>>>>> So if I understand correctly you're talking about the case:
>>>>>>>>>>>> 1. doc.setPropertyValue("foo", ...);
>>>>>>>>>>>> 2. doc.updateProperties(map);
>>>>>>>>>>>> 3. doc.setPropertyValue("bar", ...);
>>>>>>>>>>>> 4. doc.updateProperties();
>>>>>>>>>>>>
>>>>>>>>>>>> And you're asking if the "foo" change is sent with 2. or with 4.
>>>>>>>>>>>> or
>>>>>>>>>>>> discarded? I'd say let's keep this undefined, as I feel that
>>>>>>>>>>>> it's a
>>>>>>>>>>>> use pattern that's not natural. If we really want to specify
>>>>>>>>>>>> this then
>>>>>>>>>>>> I have no problem mandating that the "foo" change should be sent
>>>>>>>>>>>> with
>>>>>>>>>>>> 2. by saying that updateProperties(map) is the same as
>>>>>>>>>>>> setPropertyValue() on all the properties of the map then calling
>>>>>>>>>>>> updateProperties() with the transient map.
>>>>>>>>>>>>
>>>>>>>>>>>> Florent
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>>>>>>>>>> <st...@sap.com>           wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>
>>>>>>>>>>>>> Coming back to the cache discussion. I would like to support
>>>>>>>>>>>>> this
>>>>>>>>>>>>> proposal by Dave/Florian and think we can also delete Methods
>>>>>>>>>>>>> on
>>>>>>>>>>>>> Session
>>>>>>>>>>>>> class like cancel() and save() which are currently not
>>>>>>>>>>>>> implemented.
>>>>>>>>>>>>>
>>>>>>>>>>>>> +1 for this:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> - All write operations provided by CmisObject should
>>>>>>>>>>>>>> automatically do
>>>>>>>>>>>>>> an
>>>>>>>>>>>>>> object
>>>>>>>>>>>>>> refresh after the update. That guarantees that the object is
>>>>>>>>>>>>>> always
>>>>>>>>>>>>>> consistent.
>>>>>>>>>>>>>> The cost for this consistency is an additional call to the
>>>>>>>>>>>>>> repository.
>>>>>>>>>>>>>
>>>>>>>>>>>>>> - Is some cases you don't need or want this addition cost.
>>>>>>>>>>>>>> Lets say
>>>>>>>>>>>>>> you
>>>>>>>>>>>>>> just
>>>>>>>>>>>>>> want to update a bunch of objects but you don't work with them
>>>>>>>>>>>>>> afterwards.
>>>>>>>>>>>>>> That's what the operations provided by Session are good for.
>>>>>>>>>>>>>> They just
>>>>>>>>>>>>>> do
>>>>>>>>>>>>>> that and nothing else.
>>>>>>>>>>>>>
>>>>>>>>>>>>> About the transient support we can design this as an optional
>>>>>>>>>>>>> add on
>>>>>>>>>>>>> with
>>>>>>>>>>>>> additional interfaces and additional implementations. With a
>>>>>>>>>>>>> clear
>>>>>>>>>>>>> separation the API become easier to use.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Regards,
>>>>>>>>>>>>> Stephan
>>>
>>
>>
>>
>
>



-- 
Florent Guillaume, Director of R&D, Nuxeo
Open Source, Java EE based, Enterprise Content Management (ECM)
http://www.nuxeo.com   http://www.nuxeo.org   +33 1 40 33 79 87

Re: Proposal to clarify CmisObject caching behaviour

Posted by Florian Müller <fl...@alfresco.com>.
Hi Florent,

Could you elaborate a bit more on that proposal?
Would TransientDocument.class be an Interface or a Class?

I like the idea of adapters. But it is not intuitive that there is an 
adapter the provides a transient paradigm. Would it make sense to add 
another method that provides a shortcut to the "transient adapter"?


Thanks,

Florian


On 10/11/2010 13:27, Florent Guillaume wrote:
> I've come around to agreeing that 2. is probably better.
>
> I can see either:
>    TransientDocument transDoc = doc.createTransientDocument():
> or
>    TransientDocument transDoc = doc.getAdapter(TransientDocument.class);
>
> The latter is more extensible for other uses besides transience
> (protocol extensions, application-specific adapters).
>
> WDYT?
>
> Florent
>
>
> On Wed, Nov 10, 2010 at 10:41 AM, Florian Müller
> <fl...@alfresco.com>  wrote:
>> I would like to see that sorted out soon. There are more and more users of OpenCMIS and API changes are usually painful for them. We should also consider a new release (0.2.0) when this is done.
>>
>> So, where are we?
>>
>> The main question is where we want to handle transient data. We have two opinions:
>> 1. Transient and non-transient data access should be covered by the CmisObject interface. (Florent)
>> 2. Transient data access should be covered by a new interface and non-transient data access should be covered by the CmisObject interface. (Florian)
>>
>> Personally, I still want to go for option 2 since it provides cleaner semantics -- especially in multi-threaded environments.
>>
>> Other opinions?
>>
>>
>> - Florian
>>
>>
>> On 08/11/2010 11:51, David Caruana wrote:
>>> Have we reached a conclusion on this issue? It's been a while since we last discussed.
>>>
>>> Regards,
>>> Dave
>>>
>>> On 22 Oct 2010, at 15:06, Florian Müller wrote:
>>>
>>>> Oh, right, there is yet another option. :)
>>>>
>>>> I support all your arguments against b), c) and d). But there are also two issues with e).
>>>> 1. Which value wins if a property is changed in the transient object _and_ present in the map?
>>>> 2. save() stores the whole object. If we make ACLs and Policies transient too (do we want that?) than updateProperties() has the side effect of storing those as well.
>>>>
>>>> Which leaves us with a) which is pretty strong. And in this case I prefer two interfaces because it much is easier to understand and provides more compile checks and less runtime surprises.
>>>>
>>>>
>>>> - Florian
>>>>
>>>>
>>>> On 22/10/2010 14:44, Florent Guillaume wrote:
>>>>> On Fri, Oct 22, 2010 at 3:33 PM, Florian Müller
>>>>> <fl...@alfresco.com>     wrote:
>>>>>> So your proposal is to add a method getTransientObject() (or something like that) to CmisObject. And that method would return a transient, not thread-safe version of the object but with setProperty(), save(), etc. enabled?
>>>>>> Is that correct?
>>>>>
>>>>> Yes.
>>>>>
>>>>>> In this case we should also add a method isTransient() to CmisObject. There should be a way to discover the state of the CmisObject.
>>>>>
>>>>> Yes that would be useful.
>>>>>
>>>>>> I suggest that if the object is not transient, the transient methods should throw an IllegalStateException.
>>>>>
>>>>> Ok.
>>>>>
>>>>>> I agree that keeping the number of interfaces and classes low helps to learn and understand an API. But blending two semantics in one class could be even more confusing.
>>>>>> For example, what should happen if updateProperties(Map) is called on a transient object? There are multiple options:
>>>>>>     a) updateProperties(Map) throws an exception because it only works for non-transient objects.
>>>>>>     b) updateProperties(Map) writes instantly to the repository and the transient object is refreshed.
>>>>> (which btw means that transient changes are lost)
>>>>>>     c) updateProperties(Map) writes instantly to the repository and but object keep its (now outdated) state.
>>>>>>     d) The property map is merged with the transient properties and written when save() is called.
>>>>>
>>>>> And also:
>>>>> e) The property map is merged with the transient properties and then
>>>>> save() is automatically called.
>>>>>
>>>>>> It is not obvious. All semantics would be right and wrong at the same time.
>>>>>
>>>>> Agreed, we have to make a choice. But we would make a similar choice
>>>>> when deciding what methods would be available on the TransientDocument
>>>>> interface and what they would do.
>>>>>
>>>>> But anyway my choices in order of preference would be e) then a).
>>>>> I don't like b) because it loses changes.
>>>>> I don't like c) because there's an issue with not keeping the changes in order.
>>>>> I don't like d) because if you didn't do any transient operation it
>>>>> doesn't behave like its non-transient counterpart.
>>>>>
>>>>> Florent
>>>>>
>>>>>>
>>>>>>
>>>>>> On 22/10/2010 13:43, Florent Guillaume wrote:
>>>>>>> Hi,
>>>>>>>
>>>>>>> Looking back at your example:
>>>>>>>
>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>> transDoc.save();
>>>>>>>
>>>>>>> I agree with the need to explicitly getting a transient object if you
>>>>>>> need different semantics.
>>>>>>> One thing that will be painful though is having different classes:
>>>>>>> TransientCmisObject, TransientDocument, TransientFolder, etc.
>>>>>>> Couldn't we simply have all the methods available on the CmisObject,
>>>>>>> Document, Folder, etc. and make them throw
>>>>>>> UnsupportedOperationException when called on a non-transient object?
>>>>>>> This would tremendously help learning about the API and avoid juggling
>>>>>>> with many different interfaces for the users.
>>>>>>>
>>>>>>> Florent
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
>>>>>>> <fl...@alfresco.com>       wrote:
>>>>>>>> Hi Florent,
>>>>>>>>
>>>>>>>> Well, no, there would be no CmisObject.save() method. The save() method
>>>>>>>> would only be on the transient object.
>>>>>>>>
>>>>>>>> CmisObject would have updateProperties(Map), applyAcl(List<Ace>, List<Ace>,
>>>>>>>> AclPropagation), applyPolicy(ObjectId), etc. And all of them would write
>>>>>>>> instantly to the repository and refresh the object.
>>>>>>>>
>>>>>>>>
>>>>>>>> Florian
>>>>>>>>
>>>>>>>>
>>>>>>>> On 18/10/2010 17:49, Florent Guillaume wrote:
>>>>>>>>>
>>>>>>>>> Ok understood and agreed. There would be a new CmisObject.save() to
>>>>>>>>> replace updateProperties() then? That works for me as it's a less
>>>>>>>>> restrictive name that allows for different implementations of the
>>>>>>>>> transient space that don't deal with just properties.
>>>>>>>>>
>>>>>>>>> Regarding your examples I don't need to do all that, because in the
>>>>>>>>> Nuxeo use cases I described the client Session I'm providing to the
>>>>>>>>> user of the API is not a PersistentSessionImpl but a completely new
>>>>>>>>> Nuxeo class that does all the wrapping it needs around native Nuxeo
>>>>>>>>> objects. So I'm not constrained by the semantics of the current
>>>>>>>>> PersistentSessionImpl. It's just that I need a save()-like API to
>>>>>>>>> exist on the CmisObject. And of course I want to have semantics that
>>>>>>>>> are not too far to what's available when you use an actual remote
>>>>>>>>> connection using pure OpenCMIS PersistentSessionImpl.
>>>>>>>>>
>>>>>>>>> Florent
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>>>>>>>>> <fl...@alfresco.com>         wrote:
>>>>>>>>>>
>>>>>>>>>> Hi Florent,
>>>>>>>>>>
>>>>>>>>>> We don't want to remove the transient space entirely. The proposal is to
>>>>>>>>>> detach the transient from the non-transient part. We would have two
>>>>>>>>>> separate
>>>>>>>>>> objects.
>>>>>>>>>>
>>>>>>>>>> The non-transient object is always consistent, can be shared across
>>>>>>>>>> threads
>>>>>>>>>> and is cached. Changes are directly written to the repository. This
>>>>>>>>>> object
>>>>>>>>>> would have an updateProperties(Map) method that immediately refreshes the
>>>>>>>>>> object after the update.
>>>>>>>>>>
>>>>>>>>>> The transient object is owned by one thread and not thread safe. That
>>>>>>>>>> should
>>>>>>>>>> prevent inconsistent views on the object. This object would have
>>>>>>>>>> setProperty() and save() methods. Internally it would use the
>>>>>>>>>> non-transient
>>>>>>>>>> object to access all unchanged data. It's a wrapper around the
>>>>>>>>>> non-transient
>>>>>>>>>> object that holds the transient data.
>>>>>>>>>>
>>>>>>>>>> So you still could use the pattern that you are using today. The only
>>>>>>>>>> difference would be that you have to create a transient wrapper object.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> That could look like this:
>>>>>>>>>>
>>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>>> TransientDocument transDoc = new TransientDocument(doc);
>>>>>>>>>>
>>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>>> transDoc.save(); // that also refreshes the underlying non-transient
>>>>>>>>>> object
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Or maybe we do something like this:
>>>>>>>>>>
>>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>>>>>
>>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>>> transDoc.save();
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Florian
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>>>>>>>>
>>>>>>>>>>> Hi,
>>>>>>>>>>>
>>>>>>>>>>> In Nuxeo the OpenCMIS client API is made available locally as another
>>>>>>>>>>> API to manipulate documents, in addition to the Nuxeo native APIs.
>>>>>>>>>>>
>>>>>>>>>>> I have a problem with removing CmisObject.updateProperties() and the
>>>>>>>>>>> mini transient space because for me it's quite useful. The Nuxeo
>>>>>>>>>>> internal non-CMIS session has a notion of a property-only transient
>>>>>>>>>>> space, so in Nuxeo you update several properties and do some kind of
>>>>>>>>>>> object save() to flush them. Without a similar flushing concept on the
>>>>>>>>>>> OpenCMIS client API, I'm obliged to make a flush on every property
>>>>>>>>>>> write, which leads to severely degraded performance.
>>>>>>>>>>>
>>>>>>>>>>> If all method calls on a CmisObject immediately write everything
>>>>>>>>>>> through the network and potentially refetch a full object there will
>>>>>>>>>>> be many people that aren't happy with CMIS performance once they get
>>>>>>>>>>> to use OpenCMIS. The client API is supposed to provide some
>>>>>>>>>>> convenience to the user, and having a mini transient space for
>>>>>>>>>>> properties is IMHO the very first step of convenience. There may be
>>>>>>>>>>> problems with the semantics of interactions between this transient
>>>>>>>>>>> space and caching / refetches, but let's solve them rather than remove
>>>>>>>>>>> them.
>>>>>>>>>>>
>>>>>>>>>>> Dave wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> For example, with a transient space, what is the behaviour when
>>>>>>>>>>>> setProperty has been called and an "update" method is then called prior
>>>>>>>>>>>> to
>>>>>>>>>>>> updateProperties. Are the transient changes discarded, flushed, or just
>>>>>>>>>>>> left
>>>>>>>>>>>> as is?
>>>>>>>>>>>
>>>>>>>>>>> So if I understand correctly you're talking about the case:
>>>>>>>>>>> 1. doc.setPropertyValue("foo", ...);
>>>>>>>>>>> 2. doc.updateProperties(map);
>>>>>>>>>>> 3. doc.setPropertyValue("bar", ...);
>>>>>>>>>>> 4. doc.updateProperties();
>>>>>>>>>>>
>>>>>>>>>>> And you're asking if the "foo" change is sent with 2. or with 4. or
>>>>>>>>>>> discarded? I'd say let's keep this undefined, as I feel that it's a
>>>>>>>>>>> use pattern that's not natural. If we really want to specify this then
>>>>>>>>>>> I have no problem mandating that the "foo" change should be sent with
>>>>>>>>>>> 2. by saying that updateProperties(map) is the same as
>>>>>>>>>>> setPropertyValue() on all the properties of the map then calling
>>>>>>>>>>> updateProperties() with the transient map.
>>>>>>>>>>>
>>>>>>>>>>> Florent
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>>>>>>>>> <st...@sap.com>           wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> Hi,
>>>>>>>>>>>>
>>>>>>>>>>>> Coming back to the cache discussion. I would like to support this
>>>>>>>>>>>> proposal by Dave/Florian and think we can also delete Methods on
>>>>>>>>>>>> Session
>>>>>>>>>>>> class like cancel() and save() which are currently not implemented.
>>>>>>>>>>>>
>>>>>>>>>>>> +1 for this:
>>>>>>>>>>>>
>>>>>>>>>>>>> - All write operations provided by CmisObject should automatically do
>>>>>>>>>>>>> an
>>>>>>>>>>>>> object
>>>>>>>>>>>>> refresh after the update. That guarantees that the object is always
>>>>>>>>>>>>> consistent.
>>>>>>>>>>>>> The cost for this consistency is an additional call to the repository.
>>>>>>>>>>>>
>>>>>>>>>>>>> - Is some cases you don't need or want this addition cost. Lets say
>>>>>>>>>>>>> you
>>>>>>>>>>>>> just
>>>>>>>>>>>>> want to update a bunch of objects but you don't work with them
>>>>>>>>>>>>> afterwards.
>>>>>>>>>>>>> That's what the operations provided by Session are good for. They just
>>>>>>>>>>>>> do
>>>>>>>>>>>>> that and nothing else.
>>>>>>>>>>>>
>>>>>>>>>>>> About the transient support we can design this as an optional add on
>>>>>>>>>>>> with
>>>>>>>>>>>> additional interfaces and additional implementations. With a clear
>>>>>>>>>>>> separation the API become easier to use.
>>>>>>>>>>>>
>>>>>>>>>>>> Regards,
>>>>>>>>>>>> Stephan
>>
>
>
>


Re: Proposal to clarify CmisObject caching behaviour

Posted by Florent Guillaume <fg...@nuxeo.com>.
I've come around to agreeing that 2. is probably better.

I can see either:
  TransientDocument transDoc = doc.createTransientDocument():
or
  TransientDocument transDoc = doc.getAdapter(TransientDocument.class);

The latter is more extensible for other uses besides transience
(protocol extensions, application-specific adapters).

WDYT?

Florent


On Wed, Nov 10, 2010 at 10:41 AM, Florian Müller
<fl...@alfresco.com> wrote:
> I would like to see that sorted out soon. There are more and more users of OpenCMIS and API changes are usually painful for them. We should also consider a new release (0.2.0) when this is done.
>
> So, where are we?
>
> The main question is where we want to handle transient data. We have two opinions:
> 1. Transient and non-transient data access should be covered by the CmisObject interface. (Florent)
> 2. Transient data access should be covered by a new interface and non-transient data access should be covered by the CmisObject interface. (Florian)
>
> Personally, I still want to go for option 2 since it provides cleaner semantics -- especially in multi-threaded environments.
>
> Other opinions?
>
>
> - Florian
>
>
> On 08/11/2010 11:51, David Caruana wrote:
>> Have we reached a conclusion on this issue? It's been a while since we last discussed.
>>
>> Regards,
>> Dave
>>
>> On 22 Oct 2010, at 15:06, Florian Müller wrote:
>>
>>> Oh, right, there is yet another option. :)
>>>
>>> I support all your arguments against b), c) and d). But there are also two issues with e).
>>> 1. Which value wins if a property is changed in the transient object _and_ present in the map?
>>> 2. save() stores the whole object. If we make ACLs and Policies transient too (do we want that?) than updateProperties() has the side effect of storing those as well.
>>>
>>> Which leaves us with a) which is pretty strong. And in this case I prefer two interfaces because it much is easier to understand and provides more compile checks and less runtime surprises.
>>>
>>>
>>> - Florian
>>>
>>>
>>> On 22/10/2010 14:44, Florent Guillaume wrote:
>>>> On Fri, Oct 22, 2010 at 3:33 PM, Florian Müller
>>>> <fl...@alfresco.com>   wrote:
>>>>> So your proposal is to add a method getTransientObject() (or something like that) to CmisObject. And that method would return a transient, not thread-safe version of the object but with setProperty(), save(), etc. enabled?
>>>>> Is that correct?
>>>>
>>>> Yes.
>>>>
>>>>> In this case we should also add a method isTransient() to CmisObject. There should be a way to discover the state of the CmisObject.
>>>>
>>>> Yes that would be useful.
>>>>
>>>>> I suggest that if the object is not transient, the transient methods should throw an IllegalStateException.
>>>>
>>>> Ok.
>>>>
>>>>> I agree that keeping the number of interfaces and classes low helps to learn and understand an API. But blending two semantics in one class could be even more confusing.
>>>>> For example, what should happen if updateProperties(Map) is called on a transient object? There are multiple options:
>>>>>    a) updateProperties(Map) throws an exception because it only works for non-transient objects.
>>>>>    b) updateProperties(Map) writes instantly to the repository and the transient object is refreshed.
>>>> (which btw means that transient changes are lost)
>>>>>    c) updateProperties(Map) writes instantly to the repository and but object keep its (now outdated) state.
>>>>>    d) The property map is merged with the transient properties and written when save() is called.
>>>>
>>>> And also:
>>>> e) The property map is merged with the transient properties and then
>>>> save() is automatically called.
>>>>
>>>>> It is not obvious. All semantics would be right and wrong at the same time.
>>>>
>>>> Agreed, we have to make a choice. But we would make a similar choice
>>>> when deciding what methods would be available on the TransientDocument
>>>> interface and what they would do.
>>>>
>>>> But anyway my choices in order of preference would be e) then a).
>>>> I don't like b) because it loses changes.
>>>> I don't like c) because there's an issue with not keeping the changes in order.
>>>> I don't like d) because if you didn't do any transient operation it
>>>> doesn't behave like its non-transient counterpart.
>>>>
>>>> Florent
>>>>
>>>>>
>>>>>
>>>>> On 22/10/2010 13:43, Florent Guillaume wrote:
>>>>>> Hi,
>>>>>>
>>>>>> Looking back at your example:
>>>>>>
>>>>>> Document doc = (Document) session.getObject(id);
>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>> transDoc.save();
>>>>>>
>>>>>> I agree with the need to explicitly getting a transient object if you
>>>>>> need different semantics.
>>>>>> One thing that will be painful though is having different classes:
>>>>>> TransientCmisObject, TransientDocument, TransientFolder, etc.
>>>>>> Couldn't we simply have all the methods available on the CmisObject,
>>>>>> Document, Folder, etc. and make them throw
>>>>>> UnsupportedOperationException when called on a non-transient object?
>>>>>> This would tremendously help learning about the API and avoid juggling
>>>>>> with many different interfaces for the users.
>>>>>>
>>>>>> Florent
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
>>>>>> <fl...@alfresco.com>     wrote:
>>>>>>> Hi Florent,
>>>>>>>
>>>>>>> Well, no, there would be no CmisObject.save() method. The save() method
>>>>>>> would only be on the transient object.
>>>>>>>
>>>>>>> CmisObject would have updateProperties(Map), applyAcl(List<Ace>, List<Ace>,
>>>>>>> AclPropagation), applyPolicy(ObjectId), etc. And all of them would write
>>>>>>> instantly to the repository and refresh the object.
>>>>>>>
>>>>>>>
>>>>>>> Florian
>>>>>>>
>>>>>>>
>>>>>>> On 18/10/2010 17:49, Florent Guillaume wrote:
>>>>>>>>
>>>>>>>> Ok understood and agreed. There would be a new CmisObject.save() to
>>>>>>>> replace updateProperties() then? That works for me as it's a less
>>>>>>>> restrictive name that allows for different implementations of the
>>>>>>>> transient space that don't deal with just properties.
>>>>>>>>
>>>>>>>> Regarding your examples I don't need to do all that, because in the
>>>>>>>> Nuxeo use cases I described the client Session I'm providing to the
>>>>>>>> user of the API is not a PersistentSessionImpl but a completely new
>>>>>>>> Nuxeo class that does all the wrapping it needs around native Nuxeo
>>>>>>>> objects. So I'm not constrained by the semantics of the current
>>>>>>>> PersistentSessionImpl. It's just that I need a save()-like API to
>>>>>>>> exist on the CmisObject. And of course I want to have semantics that
>>>>>>>> are not too far to what's available when you use an actual remote
>>>>>>>> connection using pure OpenCMIS PersistentSessionImpl.
>>>>>>>>
>>>>>>>> Florent
>>>>>>>>
>>>>>>>>
>>>>>>>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>>>>>>>> <fl...@alfresco.com>       wrote:
>>>>>>>>>
>>>>>>>>> Hi Florent,
>>>>>>>>>
>>>>>>>>> We don't want to remove the transient space entirely. The proposal is to
>>>>>>>>> detach the transient from the non-transient part. We would have two
>>>>>>>>> separate
>>>>>>>>> objects.
>>>>>>>>>
>>>>>>>>> The non-transient object is always consistent, can be shared across
>>>>>>>>> threads
>>>>>>>>> and is cached. Changes are directly written to the repository. This
>>>>>>>>> object
>>>>>>>>> would have an updateProperties(Map) method that immediately refreshes the
>>>>>>>>> object after the update.
>>>>>>>>>
>>>>>>>>> The transient object is owned by one thread and not thread safe. That
>>>>>>>>> should
>>>>>>>>> prevent inconsistent views on the object. This object would have
>>>>>>>>> setProperty() and save() methods. Internally it would use the
>>>>>>>>> non-transient
>>>>>>>>> object to access all unchanged data. It's a wrapper around the
>>>>>>>>> non-transient
>>>>>>>>> object that holds the transient data.
>>>>>>>>>
>>>>>>>>> So you still could use the pattern that you are using today. The only
>>>>>>>>> difference would be that you have to create a transient wrapper object.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> That could look like this:
>>>>>>>>>
>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>> TransientDocument transDoc = new TransientDocument(doc);
>>>>>>>>>
>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>> transDoc.save(); // that also refreshes the underlying non-transient
>>>>>>>>> object
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Or maybe we do something like this:
>>>>>>>>>
>>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>>>>
>>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>>> transDoc.save();
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Florian
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>>>>>>>
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> In Nuxeo the OpenCMIS client API is made available locally as another
>>>>>>>>>> API to manipulate documents, in addition to the Nuxeo native APIs.
>>>>>>>>>>
>>>>>>>>>> I have a problem with removing CmisObject.updateProperties() and the
>>>>>>>>>> mini transient space because for me it's quite useful. The Nuxeo
>>>>>>>>>> internal non-CMIS session has a notion of a property-only transient
>>>>>>>>>> space, so in Nuxeo you update several properties and do some kind of
>>>>>>>>>> object save() to flush them. Without a similar flushing concept on the
>>>>>>>>>> OpenCMIS client API, I'm obliged to make a flush on every property
>>>>>>>>>> write, which leads to severely degraded performance.
>>>>>>>>>>
>>>>>>>>>> If all method calls on a CmisObject immediately write everything
>>>>>>>>>> through the network and potentially refetch a full object there will
>>>>>>>>>> be many people that aren't happy with CMIS performance once they get
>>>>>>>>>> to use OpenCMIS. The client API is supposed to provide some
>>>>>>>>>> convenience to the user, and having a mini transient space for
>>>>>>>>>> properties is IMHO the very first step of convenience. There may be
>>>>>>>>>> problems with the semantics of interactions between this transient
>>>>>>>>>> space and caching / refetches, but let's solve them rather than remove
>>>>>>>>>> them.
>>>>>>>>>>
>>>>>>>>>> Dave wrote:
>>>>>>>>>>>
>>>>>>>>>>> For example, with a transient space, what is the behaviour when
>>>>>>>>>>> setProperty has been called and an "update" method is then called prior
>>>>>>>>>>> to
>>>>>>>>>>> updateProperties. Are the transient changes discarded, flushed, or just
>>>>>>>>>>> left
>>>>>>>>>>> as is?
>>>>>>>>>>
>>>>>>>>>> So if I understand correctly you're talking about the case:
>>>>>>>>>> 1. doc.setPropertyValue("foo", ...);
>>>>>>>>>> 2. doc.updateProperties(map);
>>>>>>>>>> 3. doc.setPropertyValue("bar", ...);
>>>>>>>>>> 4. doc.updateProperties();
>>>>>>>>>>
>>>>>>>>>> And you're asking if the "foo" change is sent with 2. or with 4. or
>>>>>>>>>> discarded? I'd say let's keep this undefined, as I feel that it's a
>>>>>>>>>> use pattern that's not natural. If we really want to specify this then
>>>>>>>>>> I have no problem mandating that the "foo" change should be sent with
>>>>>>>>>> 2. by saying that updateProperties(map) is the same as
>>>>>>>>>> setPropertyValue() on all the properties of the map then calling
>>>>>>>>>> updateProperties() with the transient map.
>>>>>>>>>>
>>>>>>>>>> Florent
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>>>>>>>> <st...@sap.com>         wrote:
>>>>>>>>>>>
>>>>>>>>>>> Hi,
>>>>>>>>>>>
>>>>>>>>>>> Coming back to the cache discussion. I would like to support this
>>>>>>>>>>> proposal by Dave/Florian and think we can also delete Methods on
>>>>>>>>>>> Session
>>>>>>>>>>> class like cancel() and save() which are currently not implemented.
>>>>>>>>>>>
>>>>>>>>>>> +1 for this:
>>>>>>>>>>>
>>>>>>>>>>>> - All write operations provided by CmisObject should automatically do
>>>>>>>>>>>> an
>>>>>>>>>>>> object
>>>>>>>>>>>> refresh after the update. That guarantees that the object is always
>>>>>>>>>>>> consistent.
>>>>>>>>>>>> The cost for this consistency is an additional call to the repository.
>>>>>>>>>>>
>>>>>>>>>>>> - Is some cases you don't need or want this addition cost. Lets say
>>>>>>>>>>>> you
>>>>>>>>>>>> just
>>>>>>>>>>>> want to update a bunch of objects but you don't work with them
>>>>>>>>>>>> afterwards.
>>>>>>>>>>>> That's what the operations provided by Session are good for. They just
>>>>>>>>>>>> do
>>>>>>>>>>>> that and nothing else.
>>>>>>>>>>>
>>>>>>>>>>> About the transient support we can design this as an optional add on
>>>>>>>>>>> with
>>>>>>>>>>> additional interfaces and additional implementations. With a clear
>>>>>>>>>>> separation the API become easier to use.
>>>>>>>>>>>
>>>>>>>>>>> Regards,
>>>>>>>>>>> Stephan
>



-- 
Florent Guillaume, Director of R&D, Nuxeo
Open Source, Java EE based, Enterprise Content Management (ECM)
http://www.nuxeo.com   http://www.nuxeo.org   +33 1 40 33 79 87

RE: Proposal to clarify CmisObject caching behaviour

Posted by "Klevenz, Stephan" <st...@sap.com>.
Hi,

I do agree to go for a 0.2.0 release and vote for option (2). 

Regards,
Stephan

PS.: I did send a mail to mailing list using my private mail account yesterday. This did not show up. Could this an issue with Apache spam filter policy?



-----Original Message-----
From: Florian Müller [mailto:florian.mueller@alfresco.com] 
Sent: Mittwoch, 10. November 2010 10:41
To: chemistry-dev@incubator.apache.org
Subject: Re: Proposal to clarify CmisObject caching behaviour

I would like to see that sorted out soon. There are more and more users of OpenCMIS and API changes are usually painful for them. We should also consider a new release (0.2.0) when this is done.

So, where are we?

The main question is where we want to handle transient data. We have two opinions:
1. Transient and non-transient data access should be covered by the CmisObject interface. (Florent)
2. Transient data access should be covered by a new interface and non-transient data access should be covered by the CmisObject interface. (Florian)

Personally, I still want to go for option 2 since it provides cleaner semantics -- especially in multi-threaded environments.

Other opinions?


- Florian


On 08/11/2010 11:51, David Caruana wrote:
> Have we reached a conclusion on this issue? It's been a while since we last discussed.
> 
> Regards,
> Dave
> 
> On 22 Oct 2010, at 15:06, Florian Müller wrote:
> 
>> Oh, right, there is yet another option. :)
>>
>> I support all your arguments against b), c) and d). But there are also two issues with e).
>> 1. Which value wins if a property is changed in the transient object _and_ present in the map?
>> 2. save() stores the whole object. If we make ACLs and Policies transient too (do we want that?) than updateProperties() has the side effect of storing those as well.
>>
>> Which leaves us with a) which is pretty strong. And in this case I prefer two interfaces because it much is easier to understand and provides more compile checks and less runtime surprises.
>>
>>
>> - Florian
>>
>>
>> On 22/10/2010 14:44, Florent Guillaume wrote:
>>> On Fri, Oct 22, 2010 at 3:33 PM, Florian Müller
>>> <fl...@alfresco.com>   wrote:
>>>> So your proposal is to add a method getTransientObject() (or something like that) to CmisObject. And that method would return a transient, not thread-safe version of the object but with setProperty(), save(), etc. enabled?
>>>> Is that correct?
>>>
>>> Yes.
>>>
>>>> In this case we should also add a method isTransient() to CmisObject. There should be a way to discover the state of the CmisObject.
>>>
>>> Yes that would be useful.
>>>
>>>> I suggest that if the object is not transient, the transient methods should throw an IllegalStateException.
>>>
>>> Ok.
>>>
>>>> I agree that keeping the number of interfaces and classes low helps to learn and understand an API. But blending two semantics in one class could be even more confusing.
>>>> For example, what should happen if updateProperties(Map) is called on a transient object? There are multiple options:
>>>>    a) updateProperties(Map) throws an exception because it only works for non-transient objects.
>>>>    b) updateProperties(Map) writes instantly to the repository and the transient object is refreshed.
>>> (which btw means that transient changes are lost)
>>>>    c) updateProperties(Map) writes instantly to the repository and but object keep its (now outdated) state.
>>>>    d) The property map is merged with the transient properties and written when save() is called.
>>>
>>> And also:
>>> e) The property map is merged with the transient properties and then
>>> save() is automatically called.
>>>
>>>> It is not obvious. All semantics would be right and wrong at the same time.
>>>
>>> Agreed, we have to make a choice. But we would make a similar choice
>>> when deciding what methods would be available on the TransientDocument
>>> interface and what they would do.
>>>
>>> But anyway my choices in order of preference would be e) then a).
>>> I don't like b) because it loses changes.
>>> I don't like c) because there's an issue with not keeping the changes in order.
>>> I don't like d) because if you didn't do any transient operation it
>>> doesn't behave like its non-transient counterpart.
>>>
>>> Florent
>>>
>>>>
>>>>
>>>> On 22/10/2010 13:43, Florent Guillaume wrote:
>>>>> Hi,
>>>>>
>>>>> Looking back at your example:
>>>>>
>>>>> Document doc = (Document) session.getObject(id);
>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>> transDoc.setProperty("prop1", "value1");
>>>>> transDoc.setProperty("prop2", "value2");
>>>>> transDoc.save();
>>>>>
>>>>> I agree with the need to explicitly getting a transient object if you
>>>>> need different semantics.
>>>>> One thing that will be painful though is having different classes:
>>>>> TransientCmisObject, TransientDocument, TransientFolder, etc.
>>>>> Couldn't we simply have all the methods available on the CmisObject,
>>>>> Document, Folder, etc. and make them throw
>>>>> UnsupportedOperationException when called on a non-transient object?
>>>>> This would tremendously help learning about the API and avoid juggling
>>>>> with many different interfaces for the users.
>>>>>
>>>>> Florent
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
>>>>> <fl...@alfresco.com>     wrote:
>>>>>> Hi Florent,
>>>>>>
>>>>>> Well, no, there would be no CmisObject.save() method. The save() method
>>>>>> would only be on the transient object.
>>>>>>
>>>>>> CmisObject would have updateProperties(Map), applyAcl(List<Ace>, List<Ace>,
>>>>>> AclPropagation), applyPolicy(ObjectId), etc. And all of them would write
>>>>>> instantly to the repository and refresh the object.
>>>>>>
>>>>>>
>>>>>> Florian
>>>>>>
>>>>>>
>>>>>> On 18/10/2010 17:49, Florent Guillaume wrote:
>>>>>>>
>>>>>>> Ok understood and agreed. There would be a new CmisObject.save() to
>>>>>>> replace updateProperties() then? That works for me as it's a less
>>>>>>> restrictive name that allows for different implementations of the
>>>>>>> transient space that don't deal with just properties.
>>>>>>>
>>>>>>> Regarding your examples I don't need to do all that, because in the
>>>>>>> Nuxeo use cases I described the client Session I'm providing to the
>>>>>>> user of the API is not a PersistentSessionImpl but a completely new
>>>>>>> Nuxeo class that does all the wrapping it needs around native Nuxeo
>>>>>>> objects. So I'm not constrained by the semantics of the current
>>>>>>> PersistentSessionImpl. It's just that I need a save()-like API to
>>>>>>> exist on the CmisObject. And of course I want to have semantics that
>>>>>>> are not too far to what's available when you use an actual remote
>>>>>>> connection using pure OpenCMIS PersistentSessionImpl.
>>>>>>>
>>>>>>> Florent
>>>>>>>
>>>>>>>
>>>>>>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>>>>>>> <fl...@alfresco.com>       wrote:
>>>>>>>>
>>>>>>>> Hi Florent,
>>>>>>>>
>>>>>>>> We don't want to remove the transient space entirely. The proposal is to
>>>>>>>> detach the transient from the non-transient part. We would have two
>>>>>>>> separate
>>>>>>>> objects.
>>>>>>>>
>>>>>>>> The non-transient object is always consistent, can be shared across
>>>>>>>> threads
>>>>>>>> and is cached. Changes are directly written to the repository. This
>>>>>>>> object
>>>>>>>> would have an updateProperties(Map) method that immediately refreshes the
>>>>>>>> object after the update.
>>>>>>>>
>>>>>>>> The transient object is owned by one thread and not thread safe. That
>>>>>>>> should
>>>>>>>> prevent inconsistent views on the object. This object would have
>>>>>>>> setProperty() and save() methods. Internally it would use the
>>>>>>>> non-transient
>>>>>>>> object to access all unchanged data. It's a wrapper around the
>>>>>>>> non-transient
>>>>>>>> object that holds the transient data.
>>>>>>>>
>>>>>>>> So you still could use the pattern that you are using today. The only
>>>>>>>> difference would be that you have to create a transient wrapper object.
>>>>>>>>
>>>>>>>>
>>>>>>>> That could look like this:
>>>>>>>>
>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>> TransientDocument transDoc = new TransientDocument(doc);
>>>>>>>>
>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>> transDoc.save(); // that also refreshes the underlying non-transient
>>>>>>>> object
>>>>>>>>
>>>>>>>>
>>>>>>>> Or maybe we do something like this:
>>>>>>>>
>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>>>
>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>> transDoc.save();
>>>>>>>>
>>>>>>>>
>>>>>>>> Florian
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>>>>>>
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> In Nuxeo the OpenCMIS client API is made available locally as another
>>>>>>>>> API to manipulate documents, in addition to the Nuxeo native APIs.
>>>>>>>>>
>>>>>>>>> I have a problem with removing CmisObject.updateProperties() and the
>>>>>>>>> mini transient space because for me it's quite useful. The Nuxeo
>>>>>>>>> internal non-CMIS session has a notion of a property-only transient
>>>>>>>>> space, so in Nuxeo you update several properties and do some kind of
>>>>>>>>> object save() to flush them. Without a similar flushing concept on the
>>>>>>>>> OpenCMIS client API, I'm obliged to make a flush on every property
>>>>>>>>> write, which leads to severely degraded performance.
>>>>>>>>>
>>>>>>>>> If all method calls on a CmisObject immediately write everything
>>>>>>>>> through the network and potentially refetch a full object there will
>>>>>>>>> be many people that aren't happy with CMIS performance once they get
>>>>>>>>> to use OpenCMIS. The client API is supposed to provide some
>>>>>>>>> convenience to the user, and having a mini transient space for
>>>>>>>>> properties is IMHO the very first step of convenience. There may be
>>>>>>>>> problems with the semantics of interactions between this transient
>>>>>>>>> space and caching / refetches, but let's solve them rather than remove
>>>>>>>>> them.
>>>>>>>>>
>>>>>>>>> Dave wrote:
>>>>>>>>>>
>>>>>>>>>> For example, with a transient space, what is the behaviour when
>>>>>>>>>> setProperty has been called and an "update" method is then called prior
>>>>>>>>>> to
>>>>>>>>>> updateProperties. Are the transient changes discarded, flushed, or just
>>>>>>>>>> left
>>>>>>>>>> as is?
>>>>>>>>>
>>>>>>>>> So if I understand correctly you're talking about the case:
>>>>>>>>> 1. doc.setPropertyValue("foo", ...);
>>>>>>>>> 2. doc.updateProperties(map);
>>>>>>>>> 3. doc.setPropertyValue("bar", ...);
>>>>>>>>> 4. doc.updateProperties();
>>>>>>>>>
>>>>>>>>> And you're asking if the "foo" change is sent with 2. or with 4. or
>>>>>>>>> discarded? I'd say let's keep this undefined, as I feel that it's a
>>>>>>>>> use pattern that's not natural. If we really want to specify this then
>>>>>>>>> I have no problem mandating that the "foo" change should be sent with
>>>>>>>>> 2. by saying that updateProperties(map) is the same as
>>>>>>>>> setPropertyValue() on all the properties of the map then calling
>>>>>>>>> updateProperties() with the transient map.
>>>>>>>>>
>>>>>>>>> Florent
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>>>>>>> <st...@sap.com>         wrote:
>>>>>>>>>>
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> Coming back to the cache discussion. I would like to support this
>>>>>>>>>> proposal by Dave/Florian and think we can also delete Methods on
>>>>>>>>>> Session
>>>>>>>>>> class like cancel() and save() which are currently not implemented.
>>>>>>>>>>
>>>>>>>>>> +1 for this:
>>>>>>>>>>
>>>>>>>>>>> - All write operations provided by CmisObject should automatically do
>>>>>>>>>>> an
>>>>>>>>>>> object
>>>>>>>>>>> refresh after the update. That guarantees that the object is always
>>>>>>>>>>> consistent.
>>>>>>>>>>> The cost for this consistency is an additional call to the repository.
>>>>>>>>>>
>>>>>>>>>>> - Is some cases you don't need or want this addition cost. Lets say
>>>>>>>>>>> you
>>>>>>>>>>> just
>>>>>>>>>>> want to update a bunch of objects but you don't work with them
>>>>>>>>>>> afterwards.
>>>>>>>>>>> That's what the operations provided by Session are good for. They just
>>>>>>>>>>> do
>>>>>>>>>>> that and nothing else.
>>>>>>>>>>
>>>>>>>>>> About the transient support we can design this as an optional add on
>>>>>>>>>> with
>>>>>>>>>> additional interfaces and additional implementations. With a clear
>>>>>>>>>> separation the API become easier to use.
>>>>>>>>>>
>>>>>>>>>> Regards,
>>>>>>>>>> Stephan

Re: Proposal to clarify CmisObject caching behaviour

Posted by Florian Müller <fl...@alfresco.com>.
I would like to see that sorted out soon. There are more and more users of OpenCMIS and API changes are usually painful for them. We should also consider a new release (0.2.0) when this is done.

So, where are we?

The main question is where we want to handle transient data. We have two opinions:
1. Transient and non-transient data access should be covered by the CmisObject interface. (Florent)
2. Transient data access should be covered by a new interface and non-transient data access should be covered by the CmisObject interface. (Florian)

Personally, I still want to go for option 2 since it provides cleaner semantics -- especially in multi-threaded environments.

Other opinions?


- Florian


On 08/11/2010 11:51, David Caruana wrote:
> Have we reached a conclusion on this issue? It's been a while since we last discussed.
> 
> Regards,
> Dave
> 
> On 22 Oct 2010, at 15:06, Florian Müller wrote:
> 
>> Oh, right, there is yet another option. :)
>>
>> I support all your arguments against b), c) and d). But there are also two issues with e).
>> 1. Which value wins if a property is changed in the transient object _and_ present in the map?
>> 2. save() stores the whole object. If we make ACLs and Policies transient too (do we want that?) than updateProperties() has the side effect of storing those as well.
>>
>> Which leaves us with a) which is pretty strong. And in this case I prefer two interfaces because it much is easier to understand and provides more compile checks and less runtime surprises.
>>
>>
>> - Florian
>>
>>
>> On 22/10/2010 14:44, Florent Guillaume wrote:
>>> On Fri, Oct 22, 2010 at 3:33 PM, Florian Müller
>>> <fl...@alfresco.com>   wrote:
>>>> So your proposal is to add a method getTransientObject() (or something like that) to CmisObject. And that method would return a transient, not thread-safe version of the object but with setProperty(), save(), etc. enabled?
>>>> Is that correct?
>>>
>>> Yes.
>>>
>>>> In this case we should also add a method isTransient() to CmisObject. There should be a way to discover the state of the CmisObject.
>>>
>>> Yes that would be useful.
>>>
>>>> I suggest that if the object is not transient, the transient methods should throw an IllegalStateException.
>>>
>>> Ok.
>>>
>>>> I agree that keeping the number of interfaces and classes low helps to learn and understand an API. But blending two semantics in one class could be even more confusing.
>>>> For example, what should happen if updateProperties(Map) is called on a transient object? There are multiple options:
>>>>    a) updateProperties(Map) throws an exception because it only works for non-transient objects.
>>>>    b) updateProperties(Map) writes instantly to the repository and the transient object is refreshed.
>>> (which btw means that transient changes are lost)
>>>>    c) updateProperties(Map) writes instantly to the repository and but object keep its (now outdated) state.
>>>>    d) The property map is merged with the transient properties and written when save() is called.
>>>
>>> And also:
>>> e) The property map is merged with the transient properties and then
>>> save() is automatically called.
>>>
>>>> It is not obvious. All semantics would be right and wrong at the same time.
>>>
>>> Agreed, we have to make a choice. But we would make a similar choice
>>> when deciding what methods would be available on the TransientDocument
>>> interface and what they would do.
>>>
>>> But anyway my choices in order of preference would be e) then a).
>>> I don't like b) because it loses changes.
>>> I don't like c) because there's an issue with not keeping the changes in order.
>>> I don't like d) because if you didn't do any transient operation it
>>> doesn't behave like its non-transient counterpart.
>>>
>>> Florent
>>>
>>>>
>>>>
>>>> On 22/10/2010 13:43, Florent Guillaume wrote:
>>>>> Hi,
>>>>>
>>>>> Looking back at your example:
>>>>>
>>>>> Document doc = (Document) session.getObject(id);
>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>> transDoc.setProperty("prop1", "value1");
>>>>> transDoc.setProperty("prop2", "value2");
>>>>> transDoc.save();
>>>>>
>>>>> I agree with the need to explicitly getting a transient object if you
>>>>> need different semantics.
>>>>> One thing that will be painful though is having different classes:
>>>>> TransientCmisObject, TransientDocument, TransientFolder, etc.
>>>>> Couldn't we simply have all the methods available on the CmisObject,
>>>>> Document, Folder, etc. and make them throw
>>>>> UnsupportedOperationException when called on a non-transient object?
>>>>> This would tremendously help learning about the API and avoid juggling
>>>>> with many different interfaces for the users.
>>>>>
>>>>> Florent
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
>>>>> <fl...@alfresco.com>     wrote:
>>>>>> Hi Florent,
>>>>>>
>>>>>> Well, no, there would be no CmisObject.save() method. The save() method
>>>>>> would only be on the transient object.
>>>>>>
>>>>>> CmisObject would have updateProperties(Map), applyAcl(List<Ace>, List<Ace>,
>>>>>> AclPropagation), applyPolicy(ObjectId), etc. And all of them would write
>>>>>> instantly to the repository and refresh the object.
>>>>>>
>>>>>>
>>>>>> Florian
>>>>>>
>>>>>>
>>>>>> On 18/10/2010 17:49, Florent Guillaume wrote:
>>>>>>>
>>>>>>> Ok understood and agreed. There would be a new CmisObject.save() to
>>>>>>> replace updateProperties() then? That works for me as it's a less
>>>>>>> restrictive name that allows for different implementations of the
>>>>>>> transient space that don't deal with just properties.
>>>>>>>
>>>>>>> Regarding your examples I don't need to do all that, because in the
>>>>>>> Nuxeo use cases I described the client Session I'm providing to the
>>>>>>> user of the API is not a PersistentSessionImpl but a completely new
>>>>>>> Nuxeo class that does all the wrapping it needs around native Nuxeo
>>>>>>> objects. So I'm not constrained by the semantics of the current
>>>>>>> PersistentSessionImpl. It's just that I need a save()-like API to
>>>>>>> exist on the CmisObject. And of course I want to have semantics that
>>>>>>> are not too far to what's available when you use an actual remote
>>>>>>> connection using pure OpenCMIS PersistentSessionImpl.
>>>>>>>
>>>>>>> Florent
>>>>>>>
>>>>>>>
>>>>>>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>>>>>>> <fl...@alfresco.com>       wrote:
>>>>>>>>
>>>>>>>> Hi Florent,
>>>>>>>>
>>>>>>>> We don't want to remove the transient space entirely. The proposal is to
>>>>>>>> detach the transient from the non-transient part. We would have two
>>>>>>>> separate
>>>>>>>> objects.
>>>>>>>>
>>>>>>>> The non-transient object is always consistent, can be shared across
>>>>>>>> threads
>>>>>>>> and is cached. Changes are directly written to the repository. This
>>>>>>>> object
>>>>>>>> would have an updateProperties(Map) method that immediately refreshes the
>>>>>>>> object after the update.
>>>>>>>>
>>>>>>>> The transient object is owned by one thread and not thread safe. That
>>>>>>>> should
>>>>>>>> prevent inconsistent views on the object. This object would have
>>>>>>>> setProperty() and save() methods. Internally it would use the
>>>>>>>> non-transient
>>>>>>>> object to access all unchanged data. It's a wrapper around the
>>>>>>>> non-transient
>>>>>>>> object that holds the transient data.
>>>>>>>>
>>>>>>>> So you still could use the pattern that you are using today. The only
>>>>>>>> difference would be that you have to create a transient wrapper object.
>>>>>>>>
>>>>>>>>
>>>>>>>> That could look like this:
>>>>>>>>
>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>> TransientDocument transDoc = new TransientDocument(doc);
>>>>>>>>
>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>> transDoc.save(); // that also refreshes the underlying non-transient
>>>>>>>> object
>>>>>>>>
>>>>>>>>
>>>>>>>> Or maybe we do something like this:
>>>>>>>>
>>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>>>
>>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>>> transDoc.save();
>>>>>>>>
>>>>>>>>
>>>>>>>> Florian
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>>>>>>
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> In Nuxeo the OpenCMIS client API is made available locally as another
>>>>>>>>> API to manipulate documents, in addition to the Nuxeo native APIs.
>>>>>>>>>
>>>>>>>>> I have a problem with removing CmisObject.updateProperties() and the
>>>>>>>>> mini transient space because for me it's quite useful. The Nuxeo
>>>>>>>>> internal non-CMIS session has a notion of a property-only transient
>>>>>>>>> space, so in Nuxeo you update several properties and do some kind of
>>>>>>>>> object save() to flush them. Without a similar flushing concept on the
>>>>>>>>> OpenCMIS client API, I'm obliged to make a flush on every property
>>>>>>>>> write, which leads to severely degraded performance.
>>>>>>>>>
>>>>>>>>> If all method calls on a CmisObject immediately write everything
>>>>>>>>> through the network and potentially refetch a full object there will
>>>>>>>>> be many people that aren't happy with CMIS performance once they get
>>>>>>>>> to use OpenCMIS. The client API is supposed to provide some
>>>>>>>>> convenience to the user, and having a mini transient space for
>>>>>>>>> properties is IMHO the very first step of convenience. There may be
>>>>>>>>> problems with the semantics of interactions between this transient
>>>>>>>>> space and caching / refetches, but let's solve them rather than remove
>>>>>>>>> them.
>>>>>>>>>
>>>>>>>>> Dave wrote:
>>>>>>>>>>
>>>>>>>>>> For example, with a transient space, what is the behaviour when
>>>>>>>>>> setProperty has been called and an "update" method is then called prior
>>>>>>>>>> to
>>>>>>>>>> updateProperties. Are the transient changes discarded, flushed, or just
>>>>>>>>>> left
>>>>>>>>>> as is?
>>>>>>>>>
>>>>>>>>> So if I understand correctly you're talking about the case:
>>>>>>>>> 1. doc.setPropertyValue("foo", ...);
>>>>>>>>> 2. doc.updateProperties(map);
>>>>>>>>> 3. doc.setPropertyValue("bar", ...);
>>>>>>>>> 4. doc.updateProperties();
>>>>>>>>>
>>>>>>>>> And you're asking if the "foo" change is sent with 2. or with 4. or
>>>>>>>>> discarded? I'd say let's keep this undefined, as I feel that it's a
>>>>>>>>> use pattern that's not natural. If we really want to specify this then
>>>>>>>>> I have no problem mandating that the "foo" change should be sent with
>>>>>>>>> 2. by saying that updateProperties(map) is the same as
>>>>>>>>> setPropertyValue() on all the properties of the map then calling
>>>>>>>>> updateProperties() with the transient map.
>>>>>>>>>
>>>>>>>>> Florent
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>>>>>>> <st...@sap.com>         wrote:
>>>>>>>>>>
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> Coming back to the cache discussion. I would like to support this
>>>>>>>>>> proposal by Dave/Florian and think we can also delete Methods on
>>>>>>>>>> Session
>>>>>>>>>> class like cancel() and save() which are currently not implemented.
>>>>>>>>>>
>>>>>>>>>> +1 for this:
>>>>>>>>>>
>>>>>>>>>>> - All write operations provided by CmisObject should automatically do
>>>>>>>>>>> an
>>>>>>>>>>> object
>>>>>>>>>>> refresh after the update. That guarantees that the object is always
>>>>>>>>>>> consistent.
>>>>>>>>>>> The cost for this consistency is an additional call to the repository.
>>>>>>>>>>
>>>>>>>>>>> - Is some cases you don't need or want this addition cost. Lets say
>>>>>>>>>>> you
>>>>>>>>>>> just
>>>>>>>>>>> want to update a bunch of objects but you don't work with them
>>>>>>>>>>> afterwards.
>>>>>>>>>>> That's what the operations provided by Session are good for. They just
>>>>>>>>>>> do
>>>>>>>>>>> that and nothing else.
>>>>>>>>>>
>>>>>>>>>> About the transient support we can design this as an optional add on
>>>>>>>>>> with
>>>>>>>>>> additional interfaces and additional implementations. With a clear
>>>>>>>>>> separation the API become easier to use.
>>>>>>>>>>
>>>>>>>>>> Regards,
>>>>>>>>>> Stephan

Re: Proposal to clarify CmisObject caching behaviour

Posted by David Caruana <da...@alfresco.com>.
Have we reached a conclusion on this issue? It's been a while since we last discussed.

Regards,
Dave

On 22 Oct 2010, at 15:06, Florian Müller wrote:

> Oh, right, there is yet another option. :)
> 
> I support all your arguments against b), c) and d). But there are also two issues with e). 
> 1. Which value wins if a property is changed in the transient object _and_ present in the map?
> 2. save() stores the whole object. If we make ACLs and Policies transient too (do we want that?) than updateProperties() has the side effect of storing those as well. 
> 
> Which leaves us with a) which is pretty strong. And in this case I prefer two interfaces because it much is easier to understand and provides more compile checks and less runtime surprises.
> 
> 
> - Florian
> 
> 
> On 22/10/2010 14:44, Florent Guillaume wrote:
>> On Fri, Oct 22, 2010 at 3:33 PM, Florian Müller
>> <fl...@alfresco.com>  wrote:
>>> So your proposal is to add a method getTransientObject() (or something like that) to CmisObject. And that method would return a transient, not thread-safe version of the object but with setProperty(), save(), etc. enabled?
>>> Is that correct?
>> 
>> Yes.
>> 
>>> In this case we should also add a method isTransient() to CmisObject. There should be a way to discover the state of the CmisObject.
>> 
>> Yes that would be useful.
>> 
>>> I suggest that if the object is not transient, the transient methods should throw an IllegalStateException.
>> 
>> Ok.
>> 
>>> I agree that keeping the number of interfaces and classes low helps to learn and understand an API. But blending two semantics in one class could be even more confusing.
>>> For example, what should happen if updateProperties(Map) is called on a transient object? There are multiple options:
>>>   a) updateProperties(Map) throws an exception because it only works for non-transient objects.
>>>   b) updateProperties(Map) writes instantly to the repository and the transient object is refreshed.
>> (which btw means that transient changes are lost)
>>>   c) updateProperties(Map) writes instantly to the repository and but object keep its (now outdated) state.
>>>   d) The property map is merged with the transient properties and written when save() is called.
>> 
>> And also:
>> e) The property map is merged with the transient properties and then
>> save() is automatically called.
>> 
>>> It is not obvious. All semantics would be right and wrong at the same time.
>> 
>> Agreed, we have to make a choice. But we would make a similar choice
>> when deciding what methods would be available on the TransientDocument
>> interface and what they would do.
>> 
>> But anyway my choices in order of preference would be e) then a).
>> I don't like b) because it loses changes.
>> I don't like c) because there's an issue with not keeping the changes in order.
>> I don't like d) because if you didn't do any transient operation it
>> doesn't behave like its non-transient counterpart.
>> 
>> Florent
>> 
>>> 
>>> 
>>> On 22/10/2010 13:43, Florent Guillaume wrote:
>>>> Hi,
>>>> 
>>>> Looking back at your example:
>>>> 
>>>> Document doc = (Document) session.getObject(id);
>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>> transDoc.setProperty("prop1", "value1");
>>>> transDoc.setProperty("prop2", "value2");
>>>> transDoc.save();
>>>> 
>>>> I agree with the need to explicitly getting a transient object if you
>>>> need different semantics.
>>>> One thing that will be painful though is having different classes:
>>>> TransientCmisObject, TransientDocument, TransientFolder, etc.
>>>> Couldn't we simply have all the methods available on the CmisObject,
>>>> Document, Folder, etc. and make them throw
>>>> UnsupportedOperationException when called on a non-transient object?
>>>> This would tremendously help learning about the API and avoid juggling
>>>> with many different interfaces for the users.
>>>> 
>>>> Florent
>>>> 
>>>> 
>>>> 
>>>> 
>>>> On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
>>>> <fl...@alfresco.com>    wrote:
>>>>> Hi Florent,
>>>>> 
>>>>> Well, no, there would be no CmisObject.save() method. The save() method
>>>>> would only be on the transient object.
>>>>> 
>>>>> CmisObject would have updateProperties(Map), applyAcl(List<Ace>, List<Ace>,
>>>>> AclPropagation), applyPolicy(ObjectId), etc. And all of them would write
>>>>> instantly to the repository and refresh the object.
>>>>> 
>>>>> 
>>>>> Florian
>>>>> 
>>>>> 
>>>>> On 18/10/2010 17:49, Florent Guillaume wrote:
>>>>>> 
>>>>>> Ok understood and agreed. There would be a new CmisObject.save() to
>>>>>> replace updateProperties() then? That works for me as it's a less
>>>>>> restrictive name that allows for different implementations of the
>>>>>> transient space that don't deal with just properties.
>>>>>> 
>>>>>> Regarding your examples I don't need to do all that, because in the
>>>>>> Nuxeo use cases I described the client Session I'm providing to the
>>>>>> user of the API is not a PersistentSessionImpl but a completely new
>>>>>> Nuxeo class that does all the wrapping it needs around native Nuxeo
>>>>>> objects. So I'm not constrained by the semantics of the current
>>>>>> PersistentSessionImpl. It's just that I need a save()-like API to
>>>>>> exist on the CmisObject. And of course I want to have semantics that
>>>>>> are not too far to what's available when you use an actual remote
>>>>>> connection using pure OpenCMIS PersistentSessionImpl.
>>>>>> 
>>>>>> Florent
>>>>>> 
>>>>>> 
>>>>>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>>>>>> <fl...@alfresco.com>      wrote:
>>>>>>> 
>>>>>>> Hi Florent,
>>>>>>> 
>>>>>>> We don't want to remove the transient space entirely. The proposal is to
>>>>>>> detach the transient from the non-transient part. We would have two
>>>>>>> separate
>>>>>>> objects.
>>>>>>> 
>>>>>>> The non-transient object is always consistent, can be shared across
>>>>>>> threads
>>>>>>> and is cached. Changes are directly written to the repository. This
>>>>>>> object
>>>>>>> would have an updateProperties(Map) method that immediately refreshes the
>>>>>>> object after the update.
>>>>>>> 
>>>>>>> The transient object is owned by one thread and not thread safe. That
>>>>>>> should
>>>>>>> prevent inconsistent views on the object. This object would have
>>>>>>> setProperty() and save() methods. Internally it would use the
>>>>>>> non-transient
>>>>>>> object to access all unchanged data. It's a wrapper around the
>>>>>>> non-transient
>>>>>>> object that holds the transient data.
>>>>>>> 
>>>>>>> So you still could use the pattern that you are using today. The only
>>>>>>> difference would be that you have to create a transient wrapper object.
>>>>>>> 
>>>>>>> 
>>>>>>> That could look like this:
>>>>>>> 
>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>> TransientDocument transDoc = new TransientDocument(doc);
>>>>>>> 
>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>> transDoc.save(); // that also refreshes the underlying non-transient
>>>>>>> object
>>>>>>> 
>>>>>>> 
>>>>>>> Or maybe we do something like this:
>>>>>>> 
>>>>>>> Document doc = (Document) session.getObject(id);
>>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>> 
>>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>>> transDoc.save();
>>>>>>> 
>>>>>>> 
>>>>>>> Florian
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>>>>> 
>>>>>>>> Hi,
>>>>>>>> 
>>>>>>>> In Nuxeo the OpenCMIS client API is made available locally as another
>>>>>>>> API to manipulate documents, in addition to the Nuxeo native APIs.
>>>>>>>> 
>>>>>>>> I have a problem with removing CmisObject.updateProperties() and the
>>>>>>>> mini transient space because for me it's quite useful. The Nuxeo
>>>>>>>> internal non-CMIS session has a notion of a property-only transient
>>>>>>>> space, so in Nuxeo you update several properties and do some kind of
>>>>>>>> object save() to flush them. Without a similar flushing concept on the
>>>>>>>> OpenCMIS client API, I'm obliged to make a flush on every property
>>>>>>>> write, which leads to severely degraded performance.
>>>>>>>> 
>>>>>>>> If all method calls on a CmisObject immediately write everything
>>>>>>>> through the network and potentially refetch a full object there will
>>>>>>>> be many people that aren't happy with CMIS performance once they get
>>>>>>>> to use OpenCMIS. The client API is supposed to provide some
>>>>>>>> convenience to the user, and having a mini transient space for
>>>>>>>> properties is IMHO the very first step of convenience. There may be
>>>>>>>> problems with the semantics of interactions between this transient
>>>>>>>> space and caching / refetches, but let's solve them rather than remove
>>>>>>>> them.
>>>>>>>> 
>>>>>>>> Dave wrote:
>>>>>>>>> 
>>>>>>>>> For example, with a transient space, what is the behaviour when
>>>>>>>>> setProperty has been called and an "update" method is then called prior
>>>>>>>>> to
>>>>>>>>> updateProperties. Are the transient changes discarded, flushed, or just
>>>>>>>>> left
>>>>>>>>> as is?
>>>>>>>> 
>>>>>>>> So if I understand correctly you're talking about the case:
>>>>>>>> 1. doc.setPropertyValue("foo", ...);
>>>>>>>> 2. doc.updateProperties(map);
>>>>>>>> 3. doc.setPropertyValue("bar", ...);
>>>>>>>> 4. doc.updateProperties();
>>>>>>>> 
>>>>>>>> And you're asking if the "foo" change is sent with 2. or with 4. or
>>>>>>>> discarded? I'd say let's keep this undefined, as I feel that it's a
>>>>>>>> use pattern that's not natural. If we really want to specify this then
>>>>>>>> I have no problem mandating that the "foo" change should be sent with
>>>>>>>> 2. by saying that updateProperties(map) is the same as
>>>>>>>> setPropertyValue() on all the properties of the map then calling
>>>>>>>> updateProperties() with the transient map.
>>>>>>>> 
>>>>>>>> Florent
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>>>>>> <st...@sap.com>        wrote:
>>>>>>>>> 
>>>>>>>>> Hi,
>>>>>>>>> 
>>>>>>>>> Coming back to the cache discussion. I would like to support this
>>>>>>>>> proposal by Dave/Florian and think we can also delete Methods on
>>>>>>>>> Session
>>>>>>>>> class like cancel() and save() which are currently not implemented.
>>>>>>>>> 
>>>>>>>>> +1 for this:
>>>>>>>>> 
>>>>>>>>>> - All write operations provided by CmisObject should automatically do
>>>>>>>>>> an
>>>>>>>>>> object
>>>>>>>>>> refresh after the update. That guarantees that the object is always
>>>>>>>>>> consistent.
>>>>>>>>>> The cost for this consistency is an additional call to the repository.
>>>>>>>>> 
>>>>>>>>>> - Is some cases you don't need or want this addition cost. Lets say
>>>>>>>>>> you
>>>>>>>>>> just
>>>>>>>>>> want to update a bunch of objects but you don't work with them
>>>>>>>>>> afterwards.
>>>>>>>>>> That's what the operations provided by Session are good for. They just
>>>>>>>>>> do
>>>>>>>>>> that and nothing else.
>>>>>>>>> 
>>>>>>>>> About the transient support we can design this as an optional add on
>>>>>>>>> with
>>>>>>>>> additional interfaces and additional implementations. With a clear
>>>>>>>>> separation the API become easier to use.
>>>>>>>>> 
>>>>>>>>> Regards,
>>>>>>>>> Stephan
>>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> 
>>>>> 
>>>>> 
>>>> 
>>>> 
>>>> 
>>> 
>>> 
>> 
>> 
>> 
> 


Re: Proposal to clarify CmisObject caching behaviour

Posted by Florian Müller <fl...@alfresco.com>.
Oh, right, there is yet another option. :)

I support all your arguments against b), c) and d). But there are also two issues with e). 
1. Which value wins if a property is changed in the transient object _and_ present in the map?
2. save() stores the whole object. If we make ACLs and Policies transient too (do we want that?) than updateProperties() has the side effect of storing those as well. 

Which leaves us with a) which is pretty strong. And in this case I prefer two interfaces because it much is easier to understand and provides more compile checks and less runtime surprises.


- Florian


On 22/10/2010 14:44, Florent Guillaume wrote:
> On Fri, Oct 22, 2010 at 3:33 PM, Florian Müller
> <fl...@alfresco.com>  wrote:
>> So your proposal is to add a method getTransientObject() (or something like that) to CmisObject. And that method would return a transient, not thread-safe version of the object but with setProperty(), save(), etc. enabled?
>> Is that correct?
> 
> Yes.
> 
>> In this case we should also add a method isTransient() to CmisObject. There should be a way to discover the state of the CmisObject.
> 
> Yes that would be useful.
> 
>> I suggest that if the object is not transient, the transient methods should throw an IllegalStateException.
> 
> Ok.
> 
>> I agree that keeping the number of interfaces and classes low helps to learn and understand an API. But blending two semantics in one class could be even more confusing.
>> For example, what should happen if updateProperties(Map) is called on a transient object? There are multiple options:
>>    a) updateProperties(Map) throws an exception because it only works for non-transient objects.
>>    b) updateProperties(Map) writes instantly to the repository and the transient object is refreshed.
> (which btw means that transient changes are lost)
>>    c) updateProperties(Map) writes instantly to the repository and but object keep its (now outdated) state.
>>    d) The property map is merged with the transient properties and written when save() is called.
> 
> And also:
> e) The property map is merged with the transient properties and then
> save() is automatically called.
> 
>> It is not obvious. All semantics would be right and wrong at the same time.
> 
> Agreed, we have to make a choice. But we would make a similar choice
> when deciding what methods would be available on the TransientDocument
> interface and what they would do.
> 
> But anyway my choices in order of preference would be e) then a).
> I don't like b) because it loses changes.
> I don't like c) because there's an issue with not keeping the changes in order.
> I don't like d) because if you didn't do any transient operation it
> doesn't behave like its non-transient counterpart.
> 
> Florent
> 
>>
>>
>> On 22/10/2010 13:43, Florent Guillaume wrote:
>>> Hi,
>>>
>>> Looking back at your example:
>>>
>>> Document doc = (Document) session.getObject(id);
>>> TransientDocument transDoc = doc.createTransientDocument():
>>> transDoc.setProperty("prop1", "value1");
>>> transDoc.setProperty("prop2", "value2");
>>> transDoc.save();
>>>
>>> I agree with the need to explicitly getting a transient object if you
>>> need different semantics.
>>> One thing that will be painful though is having different classes:
>>> TransientCmisObject, TransientDocument, TransientFolder, etc.
>>> Couldn't we simply have all the methods available on the CmisObject,
>>> Document, Folder, etc. and make them throw
>>> UnsupportedOperationException when called on a non-transient object?
>>> This would tremendously help learning about the API and avoid juggling
>>> with many different interfaces for the users.
>>>
>>> Florent
>>>
>>>
>>>
>>>
>>> On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
>>> <fl...@alfresco.com>    wrote:
>>>> Hi Florent,
>>>>
>>>> Well, no, there would be no CmisObject.save() method. The save() method
>>>> would only be on the transient object.
>>>>
>>>> CmisObject would have updateProperties(Map), applyAcl(List<Ace>, List<Ace>,
>>>> AclPropagation), applyPolicy(ObjectId), etc. And all of them would write
>>>> instantly to the repository and refresh the object.
>>>>
>>>>
>>>> Florian
>>>>
>>>>
>>>> On 18/10/2010 17:49, Florent Guillaume wrote:
>>>>>
>>>>> Ok understood and agreed. There would be a new CmisObject.save() to
>>>>> replace updateProperties() then? That works for me as it's a less
>>>>> restrictive name that allows for different implementations of the
>>>>> transient space that don't deal with just properties.
>>>>>
>>>>> Regarding your examples I don't need to do all that, because in the
>>>>> Nuxeo use cases I described the client Session I'm providing to the
>>>>> user of the API is not a PersistentSessionImpl but a completely new
>>>>> Nuxeo class that does all the wrapping it needs around native Nuxeo
>>>>> objects. So I'm not constrained by the semantics of the current
>>>>> PersistentSessionImpl. It's just that I need a save()-like API to
>>>>> exist on the CmisObject. And of course I want to have semantics that
>>>>> are not too far to what's available when you use an actual remote
>>>>> connection using pure OpenCMIS PersistentSessionImpl.
>>>>>
>>>>> Florent
>>>>>
>>>>>
>>>>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>>>>> <fl...@alfresco.com>      wrote:
>>>>>>
>>>>>> Hi Florent,
>>>>>>
>>>>>> We don't want to remove the transient space entirely. The proposal is to
>>>>>> detach the transient from the non-transient part. We would have two
>>>>>> separate
>>>>>> objects.
>>>>>>
>>>>>> The non-transient object is always consistent, can be shared across
>>>>>> threads
>>>>>> and is cached. Changes are directly written to the repository. This
>>>>>> object
>>>>>> would have an updateProperties(Map) method that immediately refreshes the
>>>>>> object after the update.
>>>>>>
>>>>>> The transient object is owned by one thread and not thread safe. That
>>>>>> should
>>>>>> prevent inconsistent views on the object. This object would have
>>>>>> setProperty() and save() methods. Internally it would use the
>>>>>> non-transient
>>>>>> object to access all unchanged data. It's a wrapper around the
>>>>>> non-transient
>>>>>> object that holds the transient data.
>>>>>>
>>>>>> So you still could use the pattern that you are using today. The only
>>>>>> difference would be that you have to create a transient wrapper object.
>>>>>>
>>>>>>
>>>>>> That could look like this:
>>>>>>
>>>>>> Document doc = (Document) session.getObject(id);
>>>>>> TransientDocument transDoc = new TransientDocument(doc);
>>>>>>
>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>> transDoc.save(); // that also refreshes the underlying non-transient
>>>>>> object
>>>>>>
>>>>>>
>>>>>> Or maybe we do something like this:
>>>>>>
>>>>>> Document doc = (Document) session.getObject(id);
>>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>>
>>>>>> transDoc.setProperty("prop1", "value1");
>>>>>> transDoc.setProperty("prop2", "value2");
>>>>>> transDoc.save();
>>>>>>
>>>>>>
>>>>>> Florian
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> In Nuxeo the OpenCMIS client API is made available locally as another
>>>>>>> API to manipulate documents, in addition to the Nuxeo native APIs.
>>>>>>>
>>>>>>> I have a problem with removing CmisObject.updateProperties() and the
>>>>>>> mini transient space because for me it's quite useful. The Nuxeo
>>>>>>> internal non-CMIS session has a notion of a property-only transient
>>>>>>> space, so in Nuxeo you update several properties and do some kind of
>>>>>>> object save() to flush them. Without a similar flushing concept on the
>>>>>>> OpenCMIS client API, I'm obliged to make a flush on every property
>>>>>>> write, which leads to severely degraded performance.
>>>>>>>
>>>>>>> If all method calls on a CmisObject immediately write everything
>>>>>>> through the network and potentially refetch a full object there will
>>>>>>> be many people that aren't happy with CMIS performance once they get
>>>>>>> to use OpenCMIS. The client API is supposed to provide some
>>>>>>> convenience to the user, and having a mini transient space for
>>>>>>> properties is IMHO the very first step of convenience. There may be
>>>>>>> problems with the semantics of interactions between this transient
>>>>>>> space and caching / refetches, but let's solve them rather than remove
>>>>>>> them.
>>>>>>>
>>>>>>> Dave wrote:
>>>>>>>>
>>>>>>>> For example, with a transient space, what is the behaviour when
>>>>>>>> setProperty has been called and an "update" method is then called prior
>>>>>>>> to
>>>>>>>> updateProperties. Are the transient changes discarded, flushed, or just
>>>>>>>> left
>>>>>>>> as is?
>>>>>>>
>>>>>>> So if I understand correctly you're talking about the case:
>>>>>>> 1. doc.setPropertyValue("foo", ...);
>>>>>>> 2. doc.updateProperties(map);
>>>>>>> 3. doc.setPropertyValue("bar", ...);
>>>>>>> 4. doc.updateProperties();
>>>>>>>
>>>>>>> And you're asking if the "foo" change is sent with 2. or with 4. or
>>>>>>> discarded? I'd say let's keep this undefined, as I feel that it's a
>>>>>>> use pattern that's not natural. If we really want to specify this then
>>>>>>> I have no problem mandating that the "foo" change should be sent with
>>>>>>> 2. by saying that updateProperties(map) is the same as
>>>>>>> setPropertyValue() on all the properties of the map then calling
>>>>>>> updateProperties() with the transient map.
>>>>>>>
>>>>>>> Florent
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>>>>> <st...@sap.com>        wrote:
>>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> Coming back to the cache discussion. I would like to support this
>>>>>>>> proposal by Dave/Florian and think we can also delete Methods on
>>>>>>>> Session
>>>>>>>> class like cancel() and save() which are currently not implemented.
>>>>>>>>
>>>>>>>> +1 for this:
>>>>>>>>
>>>>>>>>> - All write operations provided by CmisObject should automatically do
>>>>>>>>> an
>>>>>>>>> object
>>>>>>>>> refresh after the update. That guarantees that the object is always
>>>>>>>>> consistent.
>>>>>>>>> The cost for this consistency is an additional call to the repository.
>>>>>>>>
>>>>>>>>> - Is some cases you don't need or want this addition cost. Lets say
>>>>>>>>> you
>>>>>>>>> just
>>>>>>>>> want to update a bunch of objects but you don't work with them
>>>>>>>>> afterwards.
>>>>>>>>> That's what the operations provided by Session are good for. They just
>>>>>>>>> do
>>>>>>>>> that and nothing else.
>>>>>>>>
>>>>>>>> About the transient support we can design this as an optional add on
>>>>>>>> with
>>>>>>>> additional interfaces and additional implementations. With a clear
>>>>>>>> separation the API become easier to use.
>>>>>>>>
>>>>>>>> Regards,
>>>>>>>> Stephan
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>>
>>
>>
> 
> 
> 


Re: Proposal to clarify CmisObject caching behaviour

Posted by Florent Guillaume <fg...@nuxeo.com>.
On Fri, Oct 22, 2010 at 3:33 PM, Florian Müller
<fl...@alfresco.com> wrote:
> So your proposal is to add a method getTransientObject() (or something like that) to CmisObject. And that method would return a transient, not thread-safe version of the object but with setProperty(), save(), etc. enabled?
> Is that correct?

Yes.

> In this case we should also add a method isTransient() to CmisObject. There should be a way to discover the state of the CmisObject.

Yes that would be useful.

> I suggest that if the object is not transient, the transient methods should throw an IllegalStateException.

Ok.

> I agree that keeping the number of interfaces and classes low helps to learn and understand an API. But blending two semantics in one class could be even more confusing.
> For example, what should happen if updateProperties(Map) is called on a transient object? There are multiple options:
>   a) updateProperties(Map) throws an exception because it only works for non-transient objects.
>   b) updateProperties(Map) writes instantly to the repository and the transient object is refreshed.
(which btw means that transient changes are lost)
>   c) updateProperties(Map) writes instantly to the repository and but object keep its (now outdated) state.
>   d) The property map is merged with the transient properties and written when save() is called.

And also:
e) The property map is merged with the transient properties and then
save() is automatically called.

> It is not obvious. All semantics would be right and wrong at the same time.

Agreed, we have to make a choice. But we would make a similar choice
when deciding what methods would be available on the TransientDocument
interface and what they would do.

But anyway my choices in order of preference would be e) then a).
I don't like b) because it loses changes.
I don't like c) because there's an issue with not keeping the changes in order.
I don't like d) because if you didn't do any transient operation it
doesn't behave like its non-transient counterpart.

Florent

>
>
> On 22/10/2010 13:43, Florent Guillaume wrote:
>> Hi,
>>
>> Looking back at your example:
>>
>> Document doc = (Document) session.getObject(id);
>> TransientDocument transDoc = doc.createTransientDocument():
>> transDoc.setProperty("prop1", "value1");
>> transDoc.setProperty("prop2", "value2");
>> transDoc.save();
>>
>> I agree with the need to explicitly getting a transient object if you
>> need different semantics.
>> One thing that will be painful though is having different classes:
>> TransientCmisObject, TransientDocument, TransientFolder, etc.
>> Couldn't we simply have all the methods available on the CmisObject,
>> Document, Folder, etc. and make them throw
>> UnsupportedOperationException when called on a non-transient object?
>> This would tremendously help learning about the API and avoid juggling
>> with many different interfaces for the users.
>>
>> Florent
>>
>>
>>
>>
>> On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
>> <fl...@alfresco.com>  wrote:
>>> Hi Florent,
>>>
>>> Well, no, there would be no CmisObject.save() method. The save() method
>>> would only be on the transient object.
>>>
>>> CmisObject would have updateProperties(Map), applyAcl(List<Ace>, List<Ace>,
>>> AclPropagation), applyPolicy(ObjectId), etc. And all of them would write
>>> instantly to the repository and refresh the object.
>>>
>>>
>>> Florian
>>>
>>>
>>> On 18/10/2010 17:49, Florent Guillaume wrote:
>>>>
>>>> Ok understood and agreed. There would be a new CmisObject.save() to
>>>> replace updateProperties() then? That works for me as it's a less
>>>> restrictive name that allows for different implementations of the
>>>> transient space that don't deal with just properties.
>>>>
>>>> Regarding your examples I don't need to do all that, because in the
>>>> Nuxeo use cases I described the client Session I'm providing to the
>>>> user of the API is not a PersistentSessionImpl but a completely new
>>>> Nuxeo class that does all the wrapping it needs around native Nuxeo
>>>> objects. So I'm not constrained by the semantics of the current
>>>> PersistentSessionImpl. It's just that I need a save()-like API to
>>>> exist on the CmisObject. And of course I want to have semantics that
>>>> are not too far to what's available when you use an actual remote
>>>> connection using pure OpenCMIS PersistentSessionImpl.
>>>>
>>>> Florent
>>>>
>>>>
>>>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>>>> <fl...@alfresco.com>    wrote:
>>>>>
>>>>> Hi Florent,
>>>>>
>>>>> We don't want to remove the transient space entirely. The proposal is to
>>>>> detach the transient from the non-transient part. We would have two
>>>>> separate
>>>>> objects.
>>>>>
>>>>> The non-transient object is always consistent, can be shared across
>>>>> threads
>>>>> and is cached. Changes are directly written to the repository. This
>>>>> object
>>>>> would have an updateProperties(Map) method that immediately refreshes the
>>>>> object after the update.
>>>>>
>>>>> The transient object is owned by one thread and not thread safe. That
>>>>> should
>>>>> prevent inconsistent views on the object. This object would have
>>>>> setProperty() and save() methods. Internally it would use the
>>>>> non-transient
>>>>> object to access all unchanged data. It's a wrapper around the
>>>>> non-transient
>>>>> object that holds the transient data.
>>>>>
>>>>> So you still could use the pattern that you are using today. The only
>>>>> difference would be that you have to create a transient wrapper object.
>>>>>
>>>>>
>>>>> That could look like this:
>>>>>
>>>>> Document doc = (Document) session.getObject(id);
>>>>> TransientDocument transDoc = new TransientDocument(doc);
>>>>>
>>>>> transDoc.setProperty("prop1", "value1");
>>>>> transDoc.setProperty("prop2", "value2");
>>>>> transDoc.save(); // that also refreshes the underlying non-transient
>>>>> object
>>>>>
>>>>>
>>>>> Or maybe we do something like this:
>>>>>
>>>>> Document doc = (Document) session.getObject(id);
>>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>>
>>>>> transDoc.setProperty("prop1", "value1");
>>>>> transDoc.setProperty("prop2", "value2");
>>>>> transDoc.save();
>>>>>
>>>>>
>>>>> Florian
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> In Nuxeo the OpenCMIS client API is made available locally as another
>>>>>> API to manipulate documents, in addition to the Nuxeo native APIs.
>>>>>>
>>>>>> I have a problem with removing CmisObject.updateProperties() and the
>>>>>> mini transient space because for me it's quite useful. The Nuxeo
>>>>>> internal non-CMIS session has a notion of a property-only transient
>>>>>> space, so in Nuxeo you update several properties and do some kind of
>>>>>> object save() to flush them. Without a similar flushing concept on the
>>>>>> OpenCMIS client API, I'm obliged to make a flush on every property
>>>>>> write, which leads to severely degraded performance.
>>>>>>
>>>>>> If all method calls on a CmisObject immediately write everything
>>>>>> through the network and potentially refetch a full object there will
>>>>>> be many people that aren't happy with CMIS performance once they get
>>>>>> to use OpenCMIS. The client API is supposed to provide some
>>>>>> convenience to the user, and having a mini transient space for
>>>>>> properties is IMHO the very first step of convenience. There may be
>>>>>> problems with the semantics of interactions between this transient
>>>>>> space and caching / refetches, but let's solve them rather than remove
>>>>>> them.
>>>>>>
>>>>>> Dave wrote:
>>>>>>>
>>>>>>> For example, with a transient space, what is the behaviour when
>>>>>>> setProperty has been called and an "update" method is then called prior
>>>>>>> to
>>>>>>> updateProperties. Are the transient changes discarded, flushed, or just
>>>>>>> left
>>>>>>> as is?
>>>>>>
>>>>>> So if I understand correctly you're talking about the case:
>>>>>> 1. doc.setPropertyValue("foo", ...);
>>>>>> 2. doc.updateProperties(map);
>>>>>> 3. doc.setPropertyValue("bar", ...);
>>>>>> 4. doc.updateProperties();
>>>>>>
>>>>>> And you're asking if the "foo" change is sent with 2. or with 4. or
>>>>>> discarded? I'd say let's keep this undefined, as I feel that it's a
>>>>>> use pattern that's not natural. If we really want to specify this then
>>>>>> I have no problem mandating that the "foo" change should be sent with
>>>>>> 2. by saying that updateProperties(map) is the same as
>>>>>> setPropertyValue() on all the properties of the map then calling
>>>>>> updateProperties() with the transient map.
>>>>>>
>>>>>> Florent
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>>>> <st...@sap.com>      wrote:
>>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> Coming back to the cache discussion. I would like to support this
>>>>>>> proposal by Dave/Florian and think we can also delete Methods on
>>>>>>> Session
>>>>>>> class like cancel() and save() which are currently not implemented.
>>>>>>>
>>>>>>> +1 for this:
>>>>>>>
>>>>>>>> - All write operations provided by CmisObject should automatically do
>>>>>>>> an
>>>>>>>> object
>>>>>>>> refresh after the update. That guarantees that the object is always
>>>>>>>> consistent.
>>>>>>>> The cost for this consistency is an additional call to the repository.
>>>>>>>
>>>>>>>> - Is some cases you don't need or want this addition cost. Lets say
>>>>>>>> you
>>>>>>>> just
>>>>>>>> want to update a bunch of objects but you don't work with them
>>>>>>>> afterwards.
>>>>>>>> That's what the operations provided by Session are good for. They just
>>>>>>>> do
>>>>>>>> that and nothing else.
>>>>>>>
>>>>>>> About the transient support we can design this as an optional add on
>>>>>>> with
>>>>>>> additional interfaces and additional implementations. With a clear
>>>>>>> separation the API become easier to use.
>>>>>>>
>>>>>>> Regards,
>>>>>>> Stephan
>>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>>
>
>



-- 
Florent Guillaume, Director of R&D, Nuxeo
Open Source, Java EE based, Enterprise Content Management (ECM)
http://www.nuxeo.com   http://www.nuxeo.org   +33 1 40 33 79 87

Re: Proposal to clarify CmisObject caching behaviour

Posted by Florian Müller <fl...@alfresco.com>.
So your proposal is to add a method getTransientObject() (or something like that) to CmisObject. And that method would return a transient, not thread-safe version of the object but with setProperty(), save(), etc. enabled?

Is that correct?

In this case we should also add a method isTransient() to CmisObject. There should be a way to discover the state of the CmisObject.
I suggest that if the object is not transient, the transient methods should throw an IllegalStateException.


I agree that keeping the number of interfaces and classes low helps to learn and understand an API. But blending two semantics in one class could be even more confusing.

For example, what should happen if updateProperties(Map) is called on a transient object? There are multiple options:
   a) updateProperties(Map) throws an exception because it only works for non-transient objects.
   b) updateProperties(Map) writes instantly to the repository and the transient object is refreshed.
   c) updateProperties(Map) writes instantly to the repository and but object keep its (now outdated) state.
   d) The property map is merged with the transient properties and written when save() is called.

It is not obvious. All semantics would be right and wrong at the same time.


- Florian



On 22/10/2010 13:43, Florent Guillaume wrote:
> Hi,
> 
> Looking back at your example:
> 
> Document doc = (Document) session.getObject(id);
> TransientDocument transDoc = doc.createTransientDocument():
> transDoc.setProperty("prop1", "value1");
> transDoc.setProperty("prop2", "value2");
> transDoc.save();
> 
> I agree with the need to explicitly getting a transient object if you
> need different semantics.
> One thing that will be painful though is having different classes:
> TransientCmisObject, TransientDocument, TransientFolder, etc.
> Couldn't we simply have all the methods available on the CmisObject,
> Document, Folder, etc. and make them throw
> UnsupportedOperationException when called on a non-transient object?
> This would tremendously help learning about the API and avoid juggling
> with many different interfaces for the users.
> 
> Florent
> 
> 
> 
> 
> On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
> <fl...@alfresco.com>  wrote:
>> Hi Florent,
>>
>> Well, no, there would be no CmisObject.save() method. The save() method
>> would only be on the transient object.
>>
>> CmisObject would have updateProperties(Map), applyAcl(List<Ace>, List<Ace>,
>> AclPropagation), applyPolicy(ObjectId), etc. And all of them would write
>> instantly to the repository and refresh the object.
>>
>>
>> Florian
>>
>>
>> On 18/10/2010 17:49, Florent Guillaume wrote:
>>>
>>> Ok understood and agreed. There would be a new CmisObject.save() to
>>> replace updateProperties() then? That works for me as it's a less
>>> restrictive name that allows for different implementations of the
>>> transient space that don't deal with just properties.
>>>
>>> Regarding your examples I don't need to do all that, because in the
>>> Nuxeo use cases I described the client Session I'm providing to the
>>> user of the API is not a PersistentSessionImpl but a completely new
>>> Nuxeo class that does all the wrapping it needs around native Nuxeo
>>> objects. So I'm not constrained by the semantics of the current
>>> PersistentSessionImpl. It's just that I need a save()-like API to
>>> exist on the CmisObject. And of course I want to have semantics that
>>> are not too far to what's available when you use an actual remote
>>> connection using pure OpenCMIS PersistentSessionImpl.
>>>
>>> Florent
>>>
>>>
>>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>>> <fl...@alfresco.com>    wrote:
>>>>
>>>> Hi Florent,
>>>>
>>>> We don't want to remove the transient space entirely. The proposal is to
>>>> detach the transient from the non-transient part. We would have two
>>>> separate
>>>> objects.
>>>>
>>>> The non-transient object is always consistent, can be shared across
>>>> threads
>>>> and is cached. Changes are directly written to the repository. This
>>>> object
>>>> would have an updateProperties(Map) method that immediately refreshes the
>>>> object after the update.
>>>>
>>>> The transient object is owned by one thread and not thread safe. That
>>>> should
>>>> prevent inconsistent views on the object. This object would have
>>>> setProperty() and save() methods. Internally it would use the
>>>> non-transient
>>>> object to access all unchanged data. It's a wrapper around the
>>>> non-transient
>>>> object that holds the transient data.
>>>>
>>>> So you still could use the pattern that you are using today. The only
>>>> difference would be that you have to create a transient wrapper object.
>>>>
>>>>
>>>> That could look like this:
>>>>
>>>> Document doc = (Document) session.getObject(id);
>>>> TransientDocument transDoc = new TransientDocument(doc);
>>>>
>>>> transDoc.setProperty("prop1", "value1");
>>>> transDoc.setProperty("prop2", "value2");
>>>> transDoc.save(); // that also refreshes the underlying non-transient
>>>> object
>>>>
>>>>
>>>> Or maybe we do something like this:
>>>>
>>>> Document doc = (Document) session.getObject(id);
>>>> TransientDocument transDoc = doc.createTransientDocument():
>>>>
>>>> transDoc.setProperty("prop1", "value1");
>>>> transDoc.setProperty("prop2", "value2");
>>>> transDoc.save();
>>>>
>>>>
>>>> Florian
>>>>
>>>>
>>>>
>>>>
>>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>>
>>>>> Hi,
>>>>>
>>>>> In Nuxeo the OpenCMIS client API is made available locally as another
>>>>> API to manipulate documents, in addition to the Nuxeo native APIs.
>>>>>
>>>>> I have a problem with removing CmisObject.updateProperties() and the
>>>>> mini transient space because for me it's quite useful. The Nuxeo
>>>>> internal non-CMIS session has a notion of a property-only transient
>>>>> space, so in Nuxeo you update several properties and do some kind of
>>>>> object save() to flush them. Without a similar flushing concept on the
>>>>> OpenCMIS client API, I'm obliged to make a flush on every property
>>>>> write, which leads to severely degraded performance.
>>>>>
>>>>> If all method calls on a CmisObject immediately write everything
>>>>> through the network and potentially refetch a full object there will
>>>>> be many people that aren't happy with CMIS performance once they get
>>>>> to use OpenCMIS. The client API is supposed to provide some
>>>>> convenience to the user, and having a mini transient space for
>>>>> properties is IMHO the very first step of convenience. There may be
>>>>> problems with the semantics of interactions between this transient
>>>>> space and caching / refetches, but let's solve them rather than remove
>>>>> them.
>>>>>
>>>>> Dave wrote:
>>>>>>
>>>>>> For example, with a transient space, what is the behaviour when
>>>>>> setProperty has been called and an "update" method is then called prior
>>>>>> to
>>>>>> updateProperties. Are the transient changes discarded, flushed, or just
>>>>>> left
>>>>>> as is?
>>>>>
>>>>> So if I understand correctly you're talking about the case:
>>>>> 1. doc.setPropertyValue("foo", ...);
>>>>> 2. doc.updateProperties(map);
>>>>> 3. doc.setPropertyValue("bar", ...);
>>>>> 4. doc.updateProperties();
>>>>>
>>>>> And you're asking if the "foo" change is sent with 2. or with 4. or
>>>>> discarded? I'd say let's keep this undefined, as I feel that it's a
>>>>> use pattern that's not natural. If we really want to specify this then
>>>>> I have no problem mandating that the "foo" change should be sent with
>>>>> 2. by saying that updateProperties(map) is the same as
>>>>> setPropertyValue() on all the properties of the map then calling
>>>>> updateProperties() with the transient map.
>>>>>
>>>>> Florent
>>>>>
>>>>>
>>>>>
>>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>>> <st...@sap.com>      wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> Coming back to the cache discussion. I would like to support this
>>>>>> proposal by Dave/Florian and think we can also delete Methods on
>>>>>> Session
>>>>>> class like cancel() and save() which are currently not implemented.
>>>>>>
>>>>>> +1 for this:
>>>>>>
>>>>>>> - All write operations provided by CmisObject should automatically do
>>>>>>> an
>>>>>>> object
>>>>>>> refresh after the update. That guarantees that the object is always
>>>>>>> consistent.
>>>>>>> The cost for this consistency is an additional call to the repository.
>>>>>>
>>>>>>> - Is some cases you don't need or want this addition cost. Lets say
>>>>>>> you
>>>>>>> just
>>>>>>> want to update a bunch of objects but you don't work with them
>>>>>>> afterwards.
>>>>>>> That's what the operations provided by Session are good for. They just
>>>>>>> do
>>>>>>> that and nothing else.
>>>>>>
>>>>>> About the transient support we can design this as an optional add on
>>>>>> with
>>>>>> additional interfaces and additional implementations. With a clear
>>>>>> separation the API become easier to use.
>>>>>>
>>>>>> Regards,
>>>>>> Stephan
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>>
>>
>>
> 
> 
> 


RE: Proposal to clarify CmisObject caching behavior

Posted by "Klevenz, Stephan" <st...@sap.com>.
Hi,

I have some concerns that one single CmisObject becomes too complex. But I agree that too many interfaces makes it not easier to use the API.

Would it help to keep Transient* interfaces in a separate sub package? That would underlay that the feature is optional and we can clearly separate concerns.

Regards,
Stephan


-----Original Message-----
From: Florent Guillaume [mailto:fg@nuxeo.com] 
Sent: Freitag, 22. Oktober 2010 14:43
To: chemistry-dev@incubator.apache.org
Subject: Re: Proposal to clarify CmisObject caching behaviour

Hi,

Looking back at your example:

Document doc = (Document) session.getObject(id);
TransientDocument transDoc = doc.createTransientDocument():
transDoc.setProperty("prop1", "value1");
transDoc.setProperty("prop2", "value2");
transDoc.save();

I agree with the need to explicitly getting a transient object if you
need different semantics.
One thing that will be painful though is having different classes:
TransientCmisObject, TransientDocument, TransientFolder, etc.
Couldn't we simply have all the methods available on the CmisObject,
Document, Folder, etc. and make them throw
UnsupportedOperationException when called on a non-transient object?
This would tremendously help learning about the API and avoid juggling
with many different interfaces for the users.

Florent




On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
<fl...@alfresco.com> wrote:
> Hi Florent,
>
> Well, no, there would be no CmisObject.save() method. The save() method
> would only be on the transient object.
>
> CmisObject would have updateProperties(Map), applyAcl(List<Ace>, List<Ace>,
> AclPropagation), applyPolicy(ObjectId), etc. And all of them would write
> instantly to the repository and refresh the object.
>
>
> Florian
>
>
> On 18/10/2010 17:49, Florent Guillaume wrote:
>>
>> Ok understood and agreed. There would be a new CmisObject.save() to
>> replace updateProperties() then? That works for me as it's a less
>> restrictive name that allows for different implementations of the
>> transient space that don't deal with just properties.
>>
>> Regarding your examples I don't need to do all that, because in the
>> Nuxeo use cases I described the client Session I'm providing to the
>> user of the API is not a PersistentSessionImpl but a completely new
>> Nuxeo class that does all the wrapping it needs around native Nuxeo
>> objects. So I'm not constrained by the semantics of the current
>> PersistentSessionImpl. It's just that I need a save()-like API to
>> exist on the CmisObject. And of course I want to have semantics that
>> are not too far to what's available when you use an actual remote
>> connection using pure OpenCMIS PersistentSessionImpl.
>>
>> Florent
>>
>>
>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>> <fl...@alfresco.com>  wrote:
>>>
>>> Hi Florent,
>>>
>>> We don't want to remove the transient space entirely. The proposal is to
>>> detach the transient from the non-transient part. We would have two
>>> separate
>>> objects.
>>>
>>> The non-transient object is always consistent, can be shared across
>>> threads
>>> and is cached. Changes are directly written to the repository. This
>>> object
>>> would have an updateProperties(Map) method that immediately refreshes the
>>> object after the update.
>>>
>>> The transient object is owned by one thread and not thread safe. That
>>> should
>>> prevent inconsistent views on the object. This object would have
>>> setProperty() and save() methods. Internally it would use the
>>> non-transient
>>> object to access all unchanged data. It's a wrapper around the
>>> non-transient
>>> object that holds the transient data.
>>>
>>> So you still could use the pattern that you are using today. The only
>>> difference would be that you have to create a transient wrapper object.
>>>
>>>
>>> That could look like this:
>>>
>>> Document doc = (Document) session.getObject(id);
>>> TransientDocument transDoc = new TransientDocument(doc);
>>>
>>> transDoc.setProperty("prop1", "value1");
>>> transDoc.setProperty("prop2", "value2");
>>> transDoc.save(); // that also refreshes the underlying non-transient
>>> object
>>>
>>>
>>> Or maybe we do something like this:
>>>
>>> Document doc = (Document) session.getObject(id);
>>> TransientDocument transDoc = doc.createTransientDocument():
>>>
>>> transDoc.setProperty("prop1", "value1");
>>> transDoc.setProperty("prop2", "value2");
>>> transDoc.save();
>>>
>>>
>>> Florian
>>>
>>>
>>>
>>>
>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>
>>>> Hi,
>>>>
>>>> In Nuxeo the OpenCMIS client API is made available locally as another
>>>> API to manipulate documents, in addition to the Nuxeo native APIs.
>>>>
>>>> I have a problem with removing CmisObject.updateProperties() and the
>>>> mini transient space because for me it's quite useful. The Nuxeo
>>>> internal non-CMIS session has a notion of a property-only transient
>>>> space, so in Nuxeo you update several properties and do some kind of
>>>> object save() to flush them. Without a similar flushing concept on the
>>>> OpenCMIS client API, I'm obliged to make a flush on every property
>>>> write, which leads to severely degraded performance.
>>>>
>>>> If all method calls on a CmisObject immediately write everything
>>>> through the network and potentially refetch a full object there will
>>>> be many people that aren't happy with CMIS performance once they get
>>>> to use OpenCMIS. The client API is supposed to provide some
>>>> convenience to the user, and having a mini transient space for
>>>> properties is IMHO the very first step of convenience. There may be
>>>> problems with the semantics of interactions between this transient
>>>> space and caching / refetches, but let's solve them rather than remove
>>>> them.
>>>>
>>>> Dave wrote:
>>>>>
>>>>> For example, with a transient space, what is the behaviour when
>>>>> setProperty has been called and an "update" method is then called prior
>>>>> to
>>>>> updateProperties. Are the transient changes discarded, flushed, or just
>>>>> left
>>>>> as is?
>>>>
>>>> So if I understand correctly you're talking about the case:
>>>> 1. doc.setPropertyValue("foo", ...);
>>>> 2. doc.updateProperties(map);
>>>> 3. doc.setPropertyValue("bar", ...);
>>>> 4. doc.updateProperties();
>>>>
>>>> And you're asking if the "foo" change is sent with 2. or with 4. or
>>>> discarded? I'd say let's keep this undefined, as I feel that it's a
>>>> use pattern that's not natural. If we really want to specify this then
>>>> I have no problem mandating that the "foo" change should be sent with
>>>> 2. by saying that updateProperties(map) is the same as
>>>> setPropertyValue() on all the properties of the map then calling
>>>> updateProperties() with the transient map.
>>>>
>>>> Florent
>>>>
>>>>
>>>>
>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>> <st...@sap.com>    wrote:
>>>>>
>>>>> Hi,
>>>>>
>>>>> Coming back to the cache discussion. I would like to support this
>>>>> proposal by Dave/Florian and think we can also delete Methods on
>>>>> Session
>>>>> class like cancel() and save() which are currently not implemented.
>>>>>
>>>>> +1 for this:
>>>>>
>>>>>> - All write operations provided by CmisObject should automatically do
>>>>>> an
>>>>>> object
>>>>>> refresh after the update. That guarantees that the object is always
>>>>>> consistent.
>>>>>> The cost for this consistency is an additional call to the repository.
>>>>>
>>>>>> - Is some cases you don't need or want this addition cost. Lets say
>>>>>> you
>>>>>> just
>>>>>> want to update a bunch of objects but you don't work with them
>>>>>> afterwards.
>>>>>> That's what the operations provided by Session are good for. They just
>>>>>> do
>>>>>> that and nothing else.
>>>>>
>>>>> About the transient support we can design this as an optional add on
>>>>> with
>>>>> additional interfaces and additional implementations. With a clear
>>>>> separation the API become easier to use.
>>>>>
>>>>> Regards,
>>>>> Stephan
>>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>>
>
>



-- 
Florent Guillaume, Director of R&D, Nuxeo
Open Source, Java EE based, Enterprise Content Management (ECM)
http://www.nuxeo.com   http://www.nuxeo.org   +33 1 40 33 79 87

Re: Proposal to clarify CmisObject caching behaviour

Posted by Florent Guillaume <fg...@nuxeo.com>.
Hi,

Looking back at your example:

Document doc = (Document) session.getObject(id);
TransientDocument transDoc = doc.createTransientDocument():
transDoc.setProperty("prop1", "value1");
transDoc.setProperty("prop2", "value2");
transDoc.save();

I agree with the need to explicitly getting a transient object if you
need different semantics.
One thing that will be painful though is having different classes:
TransientCmisObject, TransientDocument, TransientFolder, etc.
Couldn't we simply have all the methods available on the CmisObject,
Document, Folder, etc. and make them throw
UnsupportedOperationException when called on a non-transient object?
This would tremendously help learning about the API and avoid juggling
with many different interfaces for the users.

Florent




On Mon, Oct 18, 2010 at 10:43 PM, Florian Müller
<fl...@alfresco.com> wrote:
> Hi Florent,
>
> Well, no, there would be no CmisObject.save() method. The save() method
> would only be on the transient object.
>
> CmisObject would have updateProperties(Map), applyAcl(List<Ace>, List<Ace>,
> AclPropagation), applyPolicy(ObjectId), etc. And all of them would write
> instantly to the repository and refresh the object.
>
>
> Florian
>
>
> On 18/10/2010 17:49, Florent Guillaume wrote:
>>
>> Ok understood and agreed. There would be a new CmisObject.save() to
>> replace updateProperties() then? That works for me as it's a less
>> restrictive name that allows for different implementations of the
>> transient space that don't deal with just properties.
>>
>> Regarding your examples I don't need to do all that, because in the
>> Nuxeo use cases I described the client Session I'm providing to the
>> user of the API is not a PersistentSessionImpl but a completely new
>> Nuxeo class that does all the wrapping it needs around native Nuxeo
>> objects. So I'm not constrained by the semantics of the current
>> PersistentSessionImpl. It's just that I need a save()-like API to
>> exist on the CmisObject. And of course I want to have semantics that
>> are not too far to what's available when you use an actual remote
>> connection using pure OpenCMIS PersistentSessionImpl.
>>
>> Florent
>>
>>
>> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
>> <fl...@alfresco.com>  wrote:
>>>
>>> Hi Florent,
>>>
>>> We don't want to remove the transient space entirely. The proposal is to
>>> detach the transient from the non-transient part. We would have two
>>> separate
>>> objects.
>>>
>>> The non-transient object is always consistent, can be shared across
>>> threads
>>> and is cached. Changes are directly written to the repository. This
>>> object
>>> would have an updateProperties(Map) method that immediately refreshes the
>>> object after the update.
>>>
>>> The transient object is owned by one thread and not thread safe. That
>>> should
>>> prevent inconsistent views on the object. This object would have
>>> setProperty() and save() methods. Internally it would use the
>>> non-transient
>>> object to access all unchanged data. It's a wrapper around the
>>> non-transient
>>> object that holds the transient data.
>>>
>>> So you still could use the pattern that you are using today. The only
>>> difference would be that you have to create a transient wrapper object.
>>>
>>>
>>> That could look like this:
>>>
>>> Document doc = (Document) session.getObject(id);
>>> TransientDocument transDoc = new TransientDocument(doc);
>>>
>>> transDoc.setProperty("prop1", "value1");
>>> transDoc.setProperty("prop2", "value2");
>>> transDoc.save(); // that also refreshes the underlying non-transient
>>> object
>>>
>>>
>>> Or maybe we do something like this:
>>>
>>> Document doc = (Document) session.getObject(id);
>>> TransientDocument transDoc = doc.createTransientDocument():
>>>
>>> transDoc.setProperty("prop1", "value1");
>>> transDoc.setProperty("prop2", "value2");
>>> transDoc.save();
>>>
>>>
>>> Florian
>>>
>>>
>>>
>>>
>>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>>
>>>> Hi,
>>>>
>>>> In Nuxeo the OpenCMIS client API is made available locally as another
>>>> API to manipulate documents, in addition to the Nuxeo native APIs.
>>>>
>>>> I have a problem with removing CmisObject.updateProperties() and the
>>>> mini transient space because for me it's quite useful. The Nuxeo
>>>> internal non-CMIS session has a notion of a property-only transient
>>>> space, so in Nuxeo you update several properties and do some kind of
>>>> object save() to flush them. Without a similar flushing concept on the
>>>> OpenCMIS client API, I'm obliged to make a flush on every property
>>>> write, which leads to severely degraded performance.
>>>>
>>>> If all method calls on a CmisObject immediately write everything
>>>> through the network and potentially refetch a full object there will
>>>> be many people that aren't happy with CMIS performance once they get
>>>> to use OpenCMIS. The client API is supposed to provide some
>>>> convenience to the user, and having a mini transient space for
>>>> properties is IMHO the very first step of convenience. There may be
>>>> problems with the semantics of interactions between this transient
>>>> space and caching / refetches, but let's solve them rather than remove
>>>> them.
>>>>
>>>> Dave wrote:
>>>>>
>>>>> For example, with a transient space, what is the behaviour when
>>>>> setProperty has been called and an "update" method is then called prior
>>>>> to
>>>>> updateProperties. Are the transient changes discarded, flushed, or just
>>>>> left
>>>>> as is?
>>>>
>>>> So if I understand correctly you're talking about the case:
>>>> 1. doc.setPropertyValue("foo", ...);
>>>> 2. doc.updateProperties(map);
>>>> 3. doc.setPropertyValue("bar", ...);
>>>> 4. doc.updateProperties();
>>>>
>>>> And you're asking if the "foo" change is sent with 2. or with 4. or
>>>> discarded? I'd say let's keep this undefined, as I feel that it's a
>>>> use pattern that's not natural. If we really want to specify this then
>>>> I have no problem mandating that the "foo" change should be sent with
>>>> 2. by saying that updateProperties(map) is the same as
>>>> setPropertyValue() on all the properties of the map then calling
>>>> updateProperties() with the transient map.
>>>>
>>>> Florent
>>>>
>>>>
>>>>
>>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>>> <st...@sap.com>    wrote:
>>>>>
>>>>> Hi,
>>>>>
>>>>> Coming back to the cache discussion. I would like to support this
>>>>> proposal by Dave/Florian and think we can also delete Methods on
>>>>> Session
>>>>> class like cancel() and save() which are currently not implemented.
>>>>>
>>>>> +1 for this:
>>>>>
>>>>>> - All write operations provided by CmisObject should automatically do
>>>>>> an
>>>>>> object
>>>>>> refresh after the update. That guarantees that the object is always
>>>>>> consistent.
>>>>>> The cost for this consistency is an additional call to the repository.
>>>>>
>>>>>> - Is some cases you don't need or want this addition cost. Lets say
>>>>>> you
>>>>>> just
>>>>>> want to update a bunch of objects but you don't work with them
>>>>>> afterwards.
>>>>>> That's what the operations provided by Session are good for. They just
>>>>>> do
>>>>>> that and nothing else.
>>>>>
>>>>> About the transient support we can design this as an optional add on
>>>>> with
>>>>> additional interfaces and additional implementations. With a clear
>>>>> separation the API become easier to use.
>>>>>
>>>>> Regards,
>>>>> Stephan
>>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>>
>
>



-- 
Florent Guillaume, Director of R&D, Nuxeo
Open Source, Java EE based, Enterprise Content Management (ECM)
http://www.nuxeo.com   http://www.nuxeo.org   +33 1 40 33 79 87

Re: Proposal to clarify CmisObject caching behaviour

Posted by Florian Müller <fl...@alfresco.com>.
Hi Florent,

Well, no, there would be no CmisObject.save() method. The save() method 
would only be on the transient object.

CmisObject would have updateProperties(Map), applyAcl(List<Ace>, 
List<Ace>, AclPropagation), applyPolicy(ObjectId), etc. And all of them 
would write instantly to the repository and refresh the object.


Florian


On 18/10/2010 17:49, Florent Guillaume wrote:
> Ok understood and agreed. There would be a new CmisObject.save() to
> replace updateProperties() then? That works for me as it's a less
> restrictive name that allows for different implementations of the
> transient space that don't deal with just properties.
>
> Regarding your examples I don't need to do all that, because in the
> Nuxeo use cases I described the client Session I'm providing to the
> user of the API is not a PersistentSessionImpl but a completely new
> Nuxeo class that does all the wrapping it needs around native Nuxeo
> objects. So I'm not constrained by the semantics of the current
> PersistentSessionImpl. It's just that I need a save()-like API to
> exist on the CmisObject. And of course I want to have semantics that
> are not too far to what's available when you use an actual remote
> connection using pure OpenCMIS PersistentSessionImpl.
>
> Florent
>
>
> On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
> <fl...@alfresco.com>  wrote:
>> Hi Florent,
>>
>> We don't want to remove the transient space entirely. The proposal is to
>> detach the transient from the non-transient part. We would have two separate
>> objects.
>>
>> The non-transient object is always consistent, can be shared across threads
>> and is cached. Changes are directly written to the repository. This object
>> would have an updateProperties(Map) method that immediately refreshes the
>> object after the update.
>>
>> The transient object is owned by one thread and not thread safe. That should
>> prevent inconsistent views on the object. This object would have
>> setProperty() and save() methods. Internally it would use the non-transient
>> object to access all unchanged data. It's a wrapper around the non-transient
>> object that holds the transient data.
>>
>> So you still could use the pattern that you are using today. The only
>> difference would be that you have to create a transient wrapper object.
>>
>>
>> That could look like this:
>>
>> Document doc = (Document) session.getObject(id);
>> TransientDocument transDoc = new TransientDocument(doc);
>>
>> transDoc.setProperty("prop1", "value1");
>> transDoc.setProperty("prop2", "value2");
>> transDoc.save(); // that also refreshes the underlying non-transient object
>>
>>
>> Or maybe we do something like this:
>>
>> Document doc = (Document) session.getObject(id);
>> TransientDocument transDoc = doc.createTransientDocument():
>>
>> transDoc.setProperty("prop1", "value1");
>> transDoc.setProperty("prop2", "value2");
>> transDoc.save();
>>
>>
>> Florian
>>
>>
>>
>>
>> On 18/10/2010 16:07, Florent Guillaume wrote:
>>>
>>> Hi,
>>>
>>> In Nuxeo the OpenCMIS client API is made available locally as another
>>> API to manipulate documents, in addition to the Nuxeo native APIs.
>>>
>>> I have a problem with removing CmisObject.updateProperties() and the
>>> mini transient space because for me it's quite useful. The Nuxeo
>>> internal non-CMIS session has a notion of a property-only transient
>>> space, so in Nuxeo you update several properties and do some kind of
>>> object save() to flush them. Without a similar flushing concept on the
>>> OpenCMIS client API, I'm obliged to make a flush on every property
>>> write, which leads to severely degraded performance.
>>>
>>> If all method calls on a CmisObject immediately write everything
>>> through the network and potentially refetch a full object there will
>>> be many people that aren't happy with CMIS performance once they get
>>> to use OpenCMIS. The client API is supposed to provide some
>>> convenience to the user, and having a mini transient space for
>>> properties is IMHO the very first step of convenience. There may be
>>> problems with the semantics of interactions between this transient
>>> space and caching / refetches, but let's solve them rather than remove
>>> them.
>>>
>>> Dave wrote:
>>>>
>>>> For example, with a transient space, what is the behaviour when
>>>> setProperty has been called and an "update" method is then called prior to
>>>> updateProperties. Are the transient changes discarded, flushed, or just left
>>>> as is?
>>>
>>> So if I understand correctly you're talking about the case:
>>> 1. doc.setPropertyValue("foo", ...);
>>> 2. doc.updateProperties(map);
>>> 3. doc.setPropertyValue("bar", ...);
>>> 4. doc.updateProperties();
>>>
>>> And you're asking if the "foo" change is sent with 2. or with 4. or
>>> discarded? I'd say let's keep this undefined, as I feel that it's a
>>> use pattern that's not natural. If we really want to specify this then
>>> I have no problem mandating that the "foo" change should be sent with
>>> 2. by saying that updateProperties(map) is the same as
>>> setPropertyValue() on all the properties of the map then calling
>>> updateProperties() with the transient map.
>>>
>>> Florent
>>>
>>>
>>>
>>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>>> <st...@sap.com>    wrote:
>>>>
>>>> Hi,
>>>>
>>>> Coming back to the cache discussion. I would like to support this
>>>> proposal by Dave/Florian and think we can also delete Methods on Session
>>>> class like cancel() and save() which are currently not implemented.
>>>>
>>>> +1 for this:
>>>>
>>>>> - All write operations provided by CmisObject should automatically do an
>>>>> object
>>>>> refresh after the update. That guarantees that the object is always
>>>>> consistent.
>>>>> The cost for this consistency is an additional call to the repository.
>>>>
>>>>> - Is some cases you don't need or want this addition cost. Lets say you
>>>>> just
>>>>> want to update a bunch of objects but you don't work with them
>>>>> afterwards.
>>>>> That's what the operations provided by Session are good for. They just
>>>>> do
>>>>> that and nothing else.
>>>>
>>>> About the transient support we can design this as an optional add on with
>>>> additional interfaces and additional implementations. With a clear
>>>> separation the API become easier to use.
>>>>
>>>> Regards,
>>>> Stephan
>>>>
>>>
>>>
>>>
>>
>>
>
>
>


Re: Proposal to clarify CmisObject caching behaviour

Posted by Florent Guillaume <fg...@nuxeo.com>.
Ok understood and agreed. There would be a new CmisObject.save() to
replace updateProperties() then? That works for me as it's a less
restrictive name that allows for different implementations of the
transient space that don't deal with just properties.

Regarding your examples I don't need to do all that, because in the
Nuxeo use cases I described the client Session I'm providing to the
user of the API is not a PersistentSessionImpl but a completely new
Nuxeo class that does all the wrapping it needs around native Nuxeo
objects. So I'm not constrained by the semantics of the current
PersistentSessionImpl. It's just that I need a save()-like API to
exist on the CmisObject. And of course I want to have semantics that
are not too far to what's available when you use an actual remote
connection using pure OpenCMIS PersistentSessionImpl.

Florent


On Mon, Oct 18, 2010 at 6:06 PM, Florian Müller
<fl...@alfresco.com> wrote:
> Hi Florent,
>
> We don't want to remove the transient space entirely. The proposal is to
> detach the transient from the non-transient part. We would have two separate
> objects.
>
> The non-transient object is always consistent, can be shared across threads
> and is cached. Changes are directly written to the repository. This object
> would have an updateProperties(Map) method that immediately refreshes the
> object after the update.
>
> The transient object is owned by one thread and not thread safe. That should
> prevent inconsistent views on the object. This object would have
> setProperty() and save() methods. Internally it would use the non-transient
> object to access all unchanged data. It's a wrapper around the non-transient
> object that holds the transient data.
>
> So you still could use the pattern that you are using today. The only
> difference would be that you have to create a transient wrapper object.
>
>
> That could look like this:
>
> Document doc = (Document) session.getObject(id);
> TransientDocument transDoc = new TransientDocument(doc);
>
> transDoc.setProperty("prop1", "value1");
> transDoc.setProperty("prop2", "value2");
> transDoc.save(); // that also refreshes the underlying non-transient object
>
>
> Or maybe we do something like this:
>
> Document doc = (Document) session.getObject(id);
> TransientDocument transDoc = doc.createTransientDocument():
>
> transDoc.setProperty("prop1", "value1");
> transDoc.setProperty("prop2", "value2");
> transDoc.save();
>
>
> Florian
>
>
>
>
> On 18/10/2010 16:07, Florent Guillaume wrote:
>>
>> Hi,
>>
>> In Nuxeo the OpenCMIS client API is made available locally as another
>> API to manipulate documents, in addition to the Nuxeo native APIs.
>>
>> I have a problem with removing CmisObject.updateProperties() and the
>> mini transient space because for me it's quite useful. The Nuxeo
>> internal non-CMIS session has a notion of a property-only transient
>> space, so in Nuxeo you update several properties and do some kind of
>> object save() to flush them. Without a similar flushing concept on the
>> OpenCMIS client API, I'm obliged to make a flush on every property
>> write, which leads to severely degraded performance.
>>
>> If all method calls on a CmisObject immediately write everything
>> through the network and potentially refetch a full object there will
>> be many people that aren't happy with CMIS performance once they get
>> to use OpenCMIS. The client API is supposed to provide some
>> convenience to the user, and having a mini transient space for
>> properties is IMHO the very first step of convenience. There may be
>> problems with the semantics of interactions between this transient
>> space and caching / refetches, but let's solve them rather than remove
>> them.
>>
>> Dave wrote:
>>>
>>> For example, with a transient space, what is the behaviour when
>>> setProperty has been called and an "update" method is then called prior to
>>> updateProperties. Are the transient changes discarded, flushed, or just left
>>> as is?
>>
>> So if I understand correctly you're talking about the case:
>> 1. doc.setPropertyValue("foo", ...);
>> 2. doc.updateProperties(map);
>> 3. doc.setPropertyValue("bar", ...);
>> 4. doc.updateProperties();
>>
>> And you're asking if the "foo" change is sent with 2. or with 4. or
>> discarded? I'd say let's keep this undefined, as I feel that it's a
>> use pattern that's not natural. If we really want to specify this then
>> I have no problem mandating that the "foo" change should be sent with
>> 2. by saying that updateProperties(map) is the same as
>> setPropertyValue() on all the properties of the map then calling
>> updateProperties() with the transient map.
>>
>> Florent
>>
>>
>>
>> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
>> <st...@sap.com>  wrote:
>>>
>>> Hi,
>>>
>>> Coming back to the cache discussion. I would like to support this
>>> proposal by Dave/Florian and think we can also delete Methods on Session
>>> class like cancel() and save() which are currently not implemented.
>>>
>>> +1 for this:
>>>
>>>> - All write operations provided by CmisObject should automatically do an
>>>> object
>>>> refresh after the update. That guarantees that the object is always
>>>> consistent.
>>>> The cost for this consistency is an additional call to the repository.
>>>
>>>> - Is some cases you don't need or want this addition cost. Lets say you
>>>> just
>>>> want to update a bunch of objects but you don't work with them
>>>> afterwards.
>>>> That's what the operations provided by Session are good for. They just
>>>> do
>>>> that and nothing else.
>>>
>>> About the transient support we can design this as an optional add on with
>>> additional interfaces and additional implementations. With a clear
>>> separation the API become easier to use.
>>>
>>> Regards,
>>> Stephan
>>>
>>
>>
>>
>
>



-- 
Florent Guillaume, Director of R&D, Nuxeo
Open Source, Java EE based, Enterprise Content Management (ECM)
http://www.nuxeo.com   http://www.nuxeo.org   +33 1 40 33 79 87

Re: Proposal to clarify CmisObject caching behaviour

Posted by Florian Müller <fl...@alfresco.com>.
Hi Florent,

We don't want to remove the transient space entirely. The proposal is to 
detach the transient from the non-transient part. We would have two 
separate objects.

The non-transient object is always consistent, can be shared across 
threads and is cached. Changes are directly written to the repository. 
This object would have an updateProperties(Map) method that immediately 
refreshes the object after the update.

The transient object is owned by one thread and not thread safe. That 
should prevent inconsistent views on the object. This object would have 
setProperty() and save() methods. Internally it would use the 
non-transient object to access all unchanged data. It's a wrapper around 
the non-transient object that holds the transient data.

So you still could use the pattern that you are using today. The only 
difference would be that you have to create a transient wrapper object.


That could look like this:

Document doc = (Document) session.getObject(id);
TransientDocument transDoc = new TransientDocument(doc);

transDoc.setProperty("prop1", "value1");
transDoc.setProperty("prop2", "value2");
transDoc.save(); // that also refreshes the underlying non-transient object


Or maybe we do something like this:

Document doc = (Document) session.getObject(id);
TransientDocument transDoc = doc.createTransientDocument():

transDoc.setProperty("prop1", "value1");
transDoc.setProperty("prop2", "value2");
transDoc.save();


Florian




On 18/10/2010 16:07, Florent Guillaume wrote:
> Hi,
>
> In Nuxeo the OpenCMIS client API is made available locally as another
> API to manipulate documents, in addition to the Nuxeo native APIs.
>
> I have a problem with removing CmisObject.updateProperties() and the
> mini transient space because for me it's quite useful. The Nuxeo
> internal non-CMIS session has a notion of a property-only transient
> space, so in Nuxeo you update several properties and do some kind of
> object save() to flush them. Without a similar flushing concept on the
> OpenCMIS client API, I'm obliged to make a flush on every property
> write, which leads to severely degraded performance.
>
> If all method calls on a CmisObject immediately write everything
> through the network and potentially refetch a full object there will
> be many people that aren't happy with CMIS performance once they get
> to use OpenCMIS. The client API is supposed to provide some
> convenience to the user, and having a mini transient space for
> properties is IMHO the very first step of convenience. There may be
> problems with the semantics of interactions between this transient
> space and caching / refetches, but let's solve them rather than remove
> them.
>
> Dave wrote:
>> For example, with a transient space, what is the behaviour when setProperty has been called and an "update" method is then called prior to updateProperties. Are the transient changes discarded, flushed, or just left as is?
>
> So if I understand correctly you're talking about the case:
> 1. doc.setPropertyValue("foo", ...);
> 2. doc.updateProperties(map);
> 3. doc.setPropertyValue("bar", ...);
> 4. doc.updateProperties();
>
> And you're asking if the "foo" change is sent with 2. or with 4. or
> discarded? I'd say let's keep this undefined, as I feel that it's a
> use pattern that's not natural. If we really want to specify this then
> I have no problem mandating that the "foo" change should be sent with
> 2. by saying that updateProperties(map) is the same as
> setPropertyValue() on all the properties of the map then calling
> updateProperties() with the transient map.
>
> Florent
>
>
>
> On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
> <st...@sap.com>  wrote:
>> Hi,
>>
>> Coming back to the cache discussion. I would like to support this proposal by Dave/Florian and think we can also delete Methods on Session class like cancel() and save() which are currently not implemented.
>>
>> +1 for this:
>>
>>> - All write operations provided by CmisObject should automatically do an object
>>> refresh after the update. That guarantees that the object is always consistent.
>>> The cost for this consistency is an additional call to the repository.
>>
>>> - Is some cases you don't need or want this addition cost. Lets say you just
>>> want to update a bunch of objects but you don't work with them afterwards.
>>> That's what the operations provided by Session are good for. They just do
>>> that and nothing else.
>>
>> About the transient support we can design this as an optional add on with additional interfaces and additional implementations. With a clear separation the API become easier to use.
>>
>> Regards,
>> Stephan
>>
>
>
>


Re: Proposal to clarify CmisObject caching behaviour

Posted by Florent Guillaume <fg...@nuxeo.com>.
Hi,

In Nuxeo the OpenCMIS client API is made available locally as another
API to manipulate documents, in addition to the Nuxeo native APIs.

I have a problem with removing CmisObject.updateProperties() and the
mini transient space because for me it's quite useful. The Nuxeo
internal non-CMIS session has a notion of a property-only transient
space, so in Nuxeo you update several properties and do some kind of
object save() to flush them. Without a similar flushing concept on the
OpenCMIS client API, I'm obliged to make a flush on every property
write, which leads to severely degraded performance.

If all method calls on a CmisObject immediately write everything
through the network and potentially refetch a full object there will
be many people that aren't happy with CMIS performance once they get
to use OpenCMIS. The client API is supposed to provide some
convenience to the user, and having a mini transient space for
properties is IMHO the very first step of convenience. There may be
problems with the semantics of interactions between this transient
space and caching / refetches, but let's solve them rather than remove
them.

Dave wrote:
> For example, with a transient space, what is the behaviour when setProperty has been called and an "update" method is then called prior to updateProperties. Are the transient changes discarded, flushed, or just left as is?

So if I understand correctly you're talking about the case:
1. doc.setPropertyValue("foo", ...);
2. doc.updateProperties(map);
3. doc.setPropertyValue("bar", ...);
4. doc.updateProperties();

And you're asking if the "foo" change is sent with 2. or with 4. or
discarded? I'd say let's keep this undefined, as I feel that it's a
use pattern that's not natural. If we really want to specify this then
I have no problem mandating that the "foo" change should be sent with
2. by saying that updateProperties(map) is the same as
setPropertyValue() on all the properties of the map then calling
updateProperties() with the transient map.

Florent



On Mon, Oct 18, 2010 at 4:05 PM, Klevenz, Stephan
<st...@sap.com> wrote:
> Hi,
>
> Coming back to the cache discussion. I would like to support this proposal by Dave/Florian and think we can also delete Methods on Session class like cancel() and save() which are currently not implemented.
>
> +1 for this:
>
>> - All write operations provided by CmisObject should automatically do an object
>> refresh after the update. That guarantees that the object is always consistent.
>> The cost for this consistency is an additional call to the repository.
>
>> - Is some cases you don't need or want this addition cost. Lets say you just
>> want to update a bunch of objects but you don't work with them afterwards.
>> That's what the operations provided by Session are good for. They just do
>> that and nothing else.
>
> About the transient support we can design this as an optional add on with additional interfaces and additional implementations. With a clear separation the API become easier to use.
>
> Regards,
> Stephan
>



-- 
Florent Guillaume, Director of R&D, Nuxeo
Open Source, Java EE based, Enterprise Content Management (ECM)
http://www.nuxeo.com   http://www.nuxeo.org   +33 1 40 33 79 87

RE: Proposal to clarify CmisObject caching behaviour

Posted by "Klevenz, Stephan" <st...@sap.com>.
Hi,

Coming back to the cache discussion. I would like to support this proposal by Dave/Florian and think we can also delete Methods on Session class like cancel() and save() which are currently not implemented. 

+1 for this:

> - All write operations provided by CmisObject should automatically do an object 
> refresh after the update. That guarantees that the object is always consistent. 
> The cost for this consistency is an additional call to the repository.

> - Is some cases you don't need or want this addition cost. Lets say you just 
> want to update a bunch of objects but you don't work with them afterwards. 
> That's what the operations provided by Session are good for. They just do 
> that and nothing else.

About the transient support we can design this as an optional add on with additional interfaces and additional implementations. With a clear separation the API become easier to use.

Regards,
Stephan

Re: Proposal to clarify CmisObject caching behaviour

Posted by Florian Müller <fl...@alfresco.com>.
Hi all,

I think there are a few more things we should take into consideration. 

- Properties are just one part of the story. What about ACLs, relationships and policies? If we want a real transient and consistent behavior we would have to cache them as well and wait until save() is called before we send them to the repository. 
  I doubt that we can create a consistent object on the client side that way. We don't know the repository rules for ACLs, relationships and policies.

- What happens if save() fails? Or even worse, if one part of save() fails? For example, we could update the properties but not the ACL. The state of the object would be ambiguous.

- CmisObjects are potentially shared between threads. While one thread changes properties (or ACLs or relationships or policies), another thread would see inconsistent data.
  We could only avoid that by either create a cache per thread (which defeats the purpose of the cache) or create a copy of the cached object every time we hand one out. In the latter case all threads would have their own copies and would not see any updates other threads make. That, in turn, could end up in more refreshes and more calls to the repository.


My conclusion is that we can't build truly transient objects and we really should avoid half-transient objects by, for example, just looking at the properties.


To rephrase Davids proposal a bit:

- All write operations provided by CmisObject should automatically do an object refresh after the update. That guarantees that the object is always consistent. The cost for this consistency is an additional call to the repository.

- Is some cases you don't need or want this addition cost. Lets say you just want to update a bunch of objects but you don't work with them afterwards. That's what the operations provided by Session are good for. They just do that and nothing else.



I understand that the transient behavior is quite useful in some scenarios. But it simply doesn't work in multi-threaded environments. What we can do is to provide transient wrapper classes. Objects of these classes are not cached and owned by _one_ thread. At their core they reference and redirect calls to a consistent and shared CmisObject. But they can intercept calls and add transient behavior.
getProperty, for example, could look like that:


public <T> Property<T> getProperty(String id) {
    if(transientProperties.contains(id)) {
        return (Property<T>) transientProperties.get(id);
    }

    return (Property<T>) sharedObject.getProperty(id);
}


A thread using such a wrapper object knows that it might be inconsistent and it could throw it away if save() fails and start over. 


- Florian



On 13/10/2010 08:44, Klevenz, Stephan wrote:
> Hi David,
> 
> Thanks for starting this discussion. You are right because of the current cache behavior of the implementation also with relation to the usage of API is not easy to understand.
> 
> Basic idea behind the cache behavior can be described in 3 steps:
> 
> 1) query for an object and specify filters and put it in the cache
> 2) read from the cached object and write to the cached object while using convenient micro operations (set and get property).
> 3) write back changes of the cached objet to the persistency (save)
> 
> For 2) only that information is available that was specified by the filter in 1). Additional information would require another query.
> 
> I would like to keep this behavior because it makes it easier to use API within another framework where someone has to implement a callback not having the context for a full service call or cannot influence how many times the callback is executed just to return the same information.
> 
> Confusing is that there are some methods calls on CmisObject level that bypasses the cache. updateProperties() for instance.
> 
> What do you think to come up with this rule set:
> 
> 1) All methods on CmisObject level operate always on cache data. The programming paradigm would be query - modify -save.
> 2) All modification operations on the Session level are not cached and will be directly routed to the backend.
> 
> Here is some pseudo code of a cached scenario:
> 
> Session s = ...;
> Document doc = s.getObject( ... with filter ... );
> doc.setProperty( ... );
> doc.updateProperties( ... );
> if (ok) {
> 	doc.save();
> }
> 
> If doc is not saved then the corresponding object in the backend is not modified.
> 
> A non cached pseudo code looks like this:
> 
> Session s = ...;
> s.updateProperties( objecteId, .... );
> 
> If we could agree on such a rule then we have to re-work CmisObject to remove methods that cannot be cached and add that methods to the Session class. Some methods could be exist twice, one at the CmisObject (cached) and one at the Session (not cached).
> 
> WDYT?
> 
> Regards,
> Stephan
> 
> 
> 
> 
> -----Original Message-----
> From: David Caruana [mailto:david.caruana@alfresco.com]
> Sent: Dienstag, 12. Oktober 2010 18:19
> To: chemistry-dev@incubator.apache.org
> Subject: Re: Proposal to clarify CmisObject caching behaviour
> 
> On 12 Oct 2010, at 16:22, Florent Guillaume wrote:
> 
>> Hi David,
>>
>> I'm a bit confused by some of the vocabulary I must confess. Could we
>> make sure we don't confuse the term "cache" and the term "transient
>> space", as they have different uses.
> 
> Of course.
> 
>>
>> So do you want to remove completely any transient space and only have
>> methods that write to the remote side on each method call? So, do you
>> want to remove the fact that we can do:
>>   object.setProperty("foo1", "bar1");
>>   object.setProperty("foo2", "bar2");
>>   ...
>>   object.updateProperties();
>> i.e. today there's a mini transient space tied to the properties of
>> the object, flushed on updateProperties. I think this is quite useful
>> as it avoids having the user building a map by hand and passing it to
>> updateProperties, which is ugly for a high-level interface.
> 
> Yes, the proposal is to remove the mini transient space. The reason is to simplify behaviour if we were to introduce a CmisObject implementation that always refreshed its cache on updates. For example, with a transient space, what is the behaviour when setProperty has been called and an "update" method is then called prior to updateProperties. Are the transient changes discarded, flushed, or just left as is?
> 
>>
>> I'm ok with most methods that can do remote writes returning a CmisObject.
>>
>> But I don't like removing convenience methods on CmisObject like
>> getRelationships, getAcl, etc. as they provide convenient access to
>> the users.
> 
> There would still be the methods getRelationships() and getAcl(), but they would only return what has already been cached (as they do today). Currently, there's also getRelationships(boolean, RelationshipDirection, ObjectType, OperationContext) and getAcls(boolean) which go direct to the repository. It's these that I propose are moved to Session.
> 
>>
>> OTOH I'm completely for clarifying the caching aspects, for instance
>> it's not clear today when caches are invalidated or updated, or what
>> happens when you ask for a property that's not in the initial property
>> filter that led to the creation of the object (in a number of my unit
>> tests in Nuxeo I have to refresh() explicitly but this shouldn't be
>> needed when all the writes were mine).
> 
> Indeed, this is the confusion I'm trying to remove with this proposal. Admittedly, there is much to discuss, and the proposal is only a starting point, but I wanted to open up the discussion early to determine if this problem is severe enough to tackle.
> 
> Regards,
> Dave
> 
>>
>> Florent
>>
>>
>>
>> On Tue, Oct 12, 2010 at 12:49 PM, David Caruana
>> <da...@alfresco.com>  wrote:
>>> Currently, we only have one implementation of Session - PersistentSessionImpl. However, the OpenCMIS client API suggests transient behaviour both in its API definition and behaviour, which I believe can be confusing for users. In particular, when does OpenCMIS read information from the cache vs from the repository, and when does OpenCMIS implicitly update an item in its cache.
>>>
>>> I'd like to present the following changes in an attempt to clarify the above and trigger discussion on how to improve things in this area...
>>>
>>> 1) All methods on CmisObject operate against the cache. This means that reading a value from an item reads the value from the item in the cache, and updates to the item change the cache i.e. refresh the item in the cache. Methods that read directly from the repository move to Session. So, the proposal is:
>>>
>>> Remove the following from CmisObject...
>>> CmisObject.setName(String)
>>> CmisObject.setProperty(String, Object)
>>> CmisObject.updateProperties()
>>>
>>> Change CmisObject.updateProperties...
>>> CmisObject CmisObject.updateProperties(Map<String, ?>)    (Note: return CmisObject instead of ObjectId)
>>>
>>> Note: If the repository creates a new version, a new CmisObject is returned, otherwise the existing CmisObject is refreshed in the cache and returned.
>>>
>>> The following 'update' methods are also modified to refresh the item in the cache after update:
>>>
>>> void CmisObject.applyPolicy(ObjectId...)    (Note: accept vararg of policy ids)
>>> void CmisObject.removePolicy(ObjectId...)   (Note: accept vararg of policy ids)
>>> Acl CmisObject.applyAcl(List<Ace>, List<Ace>, AclPropagation)
>>> Acl CmisObject.addAcl(List<Ace>, AclPropagation)   (Note: also return Acl to be consistent with applyAcl)
>>> Acl CmisObject.removeAcl(List<Ace>, AclPropagation)   (Note: also return Acl to be consistent with applyAcl)
>>>
>>> Note: applyPolicy and removePolicy are also changed to accept a vararg of ObjectIds.
>>>
>>> For use cases where the refresh of an item after update is not necessary, the Session interface is used instead. So, the proposal is...
>>>
>>> Move following methods from CmisObject to Session...
>>>
>>> ItemIterable<Relationship>  Session.getRelationships(ObjectId, boolean, RelationshipDirection, ObjectType, OperationContext)
>>> Acl Session.getAcl(ObjectId, boolean)
>>>
>>> Add...
>>>
>>> ObjectId Session.updateProperties(ObjectId, Map<String, ?>)
>>> void applyPolicy(ObjectId, ObjectId...)
>>> void removePolicy(ObjectId, ObjectId...)
>>> Acl applyAcl(ObjectId, List<Ace>  addAces, List<Ace>  removeAces, AclPropagation aclPropagation)
>>> Acl getAcl(ObjectId, boolean onlyBasicPermissions)
>>>
>>> 2) Following the pattern in 1), setting content on a Document alters slightly too.
>>>
>>> Document setContentStream(ContentStream contentStream, boolean overwrite)
>>> Document deleteContentStream()
>>>
>>> Instead of returning ObjectId, the proposal is to return Document. Depending on the repository, the document may be the same item as before (updated in the cache), or a new Document, to represent a new version.
>>>
>>> Also add to Session...
>>>
>>> ObjectId setContentStream(ObjectId, ContentStream contentStream, boolean overwrite)
>>> ObjectId deleteContentStream(ObjectId)
>>>
>>> 3) Remove transient methods from Session.
>>>
>>> Until we've thought through transient session behaviour I propose we remove the following methods:
>>>
>>> Session.save()
>>> Session.cancel()
>>>
>>> Regards,
>>> Dave
>>
>>
>>
>> -- 
>> Florent Guillaume, Director of R&D, Nuxeo
>> Open Source, Java EE based, Enterprise Content Management (ECM)
>> http://www.nuxeo.com   http://www.nuxeo.org   +33 1 40 33 79 87
> 


RE: Proposal to clarify CmisObject caching behaviour

Posted by "Klevenz, Stephan" <st...@sap.com>.
Hi David,

Thanks for starting this discussion. You are right because of the current cache behavior of the implementation also with relation to the usage of API is not easy to understand.

Basic idea behind the cache behavior can be described in 3 steps:

1) query for an object and specify filters and put it in the cache
2) read from the cached object and write to the cached object while using convenient micro operations (set and get property).
3) write back changes of the cached objet to the persistency (save)

For 2) only that information is available that was specified by the filter in 1). Additional information would require another query.

I would like to keep this behavior because it makes it easier to use API within another framework where someone has to implement a callback not having the context for a full service call or cannot influence how many times the callback is executed just to return the same information. 

Confusing is that there are some methods calls on CmisObject level that bypasses the cache. updateProperties() for instance.

What do you think to come up with this rule set:

1) All methods on CmisObject level operate always on cache data. The programming paradigm would be query - modify -save.
2) All modification operations on the Session level are not cached and will be directly routed to the backend.

Here is some pseudo code of a cached scenario:

Session s = ...;
Document doc = s.getObject( ... with filter ... );
doc.setProperty( ... );
doc.updateProperties( ... );
if (ok) {
	doc.save(); 
}

If doc is not saved then the corresponding object in the backend is not modified.

A non cached pseudo code looks like this:

Session s = ...;
s.updateProperties( objecteId, .... );

If we could agree on such a rule then we have to re-work CmisObject to remove methods that cannot be cached and add that methods to the Session class. Some methods could be exist twice, one at the CmisObject (cached) and one at the Session (not cached).

WDYT?

Regards,
Stephan




-----Original Message-----
From: David Caruana [mailto:david.caruana@alfresco.com] 
Sent: Dienstag, 12. Oktober 2010 18:19
To: chemistry-dev@incubator.apache.org
Subject: Re: Proposal to clarify CmisObject caching behaviour

On 12 Oct 2010, at 16:22, Florent Guillaume wrote:

> Hi David,
> 
> I'm a bit confused by some of the vocabulary I must confess. Could we
> make sure we don't confuse the term "cache" and the term "transient
> space", as they have different uses.

Of course.

> 
> So do you want to remove completely any transient space and only have
> methods that write to the remote side on each method call? So, do you
> want to remove the fact that we can do:
>  object.setProperty("foo1", "bar1");
>  object.setProperty("foo2", "bar2");
>  ...
>  object.updateProperties();
> i.e. today there's a mini transient space tied to the properties of
> the object, flushed on updateProperties. I think this is quite useful
> as it avoids having the user building a map by hand and passing it to
> updateProperties, which is ugly for a high-level interface.

Yes, the proposal is to remove the mini transient space. The reason is to simplify behaviour if we were to introduce a CmisObject implementation that always refreshed its cache on updates. For example, with a transient space, what is the behaviour when setProperty has been called and an "update" method is then called prior to updateProperties. Are the transient changes discarded, flushed, or just left as is?

> 
> I'm ok with most methods that can do remote writes returning a CmisObject.
> 
> But I don't like removing convenience methods on CmisObject like
> getRelationships, getAcl, etc. as they provide convenient access to
> the users.

There would still be the methods getRelationships() and getAcl(), but they would only return what has already been cached (as they do today). Currently, there's also getRelationships(boolean, RelationshipDirection, ObjectType, OperationContext) and getAcls(boolean) which go direct to the repository. It's these that I propose are moved to Session.

> 
> OTOH I'm completely for clarifying the caching aspects, for instance
> it's not clear today when caches are invalidated or updated, or what
> happens when you ask for a property that's not in the initial property
> filter that led to the creation of the object (in a number of my unit
> tests in Nuxeo I have to refresh() explicitly but this shouldn't be
> needed when all the writes were mine).

Indeed, this is the confusion I'm trying to remove with this proposal. Admittedly, there is much to discuss, and the proposal is only a starting point, but I wanted to open up the discussion early to determine if this problem is severe enough to tackle.

Regards,
Dave

> 
> Florent
> 
> 
> 
> On Tue, Oct 12, 2010 at 12:49 PM, David Caruana
> <da...@alfresco.com> wrote:
>> Currently, we only have one implementation of Session - PersistentSessionImpl. However, the OpenCMIS client API suggests transient behaviour both in its API definition and behaviour, which I believe can be confusing for users. In particular, when does OpenCMIS read information from the cache vs from the repository, and when does OpenCMIS implicitly update an item in its cache.
>> 
>> I'd like to present the following changes in an attempt to clarify the above and trigger discussion on how to improve things in this area...
>> 
>> 1) All methods on CmisObject operate against the cache. This means that reading a value from an item reads the value from the item in the cache, and updates to the item change the cache i.e. refresh the item in the cache. Methods that read directly from the repository move to Session. So, the proposal is:
>> 
>> Remove the following from CmisObject...
>> CmisObject.setName(String)
>> CmisObject.setProperty(String, Object)
>> CmisObject.updateProperties()
>> 
>> Change CmisObject.updateProperties...
>> CmisObject CmisObject.updateProperties(Map<String, ?>)    (Note: return CmisObject instead of ObjectId)
>> 
>> Note: If the repository creates a new version, a new CmisObject is returned, otherwise the existing CmisObject is refreshed in the cache and returned.
>> 
>> The following 'update' methods are also modified to refresh the item in the cache after update:
>> 
>> void CmisObject.applyPolicy(ObjectId...)    (Note: accept vararg of policy ids)
>> void CmisObject.removePolicy(ObjectId...)   (Note: accept vararg of policy ids)
>> Acl CmisObject.applyAcl(List<Ace>, List<Ace>, AclPropagation)
>> Acl CmisObject.addAcl(List<Ace>, AclPropagation)   (Note: also return Acl to be consistent with applyAcl)
>> Acl CmisObject.removeAcl(List<Ace>, AclPropagation)   (Note: also return Acl to be consistent with applyAcl)
>> 
>> Note: applyPolicy and removePolicy are also changed to accept a vararg of ObjectIds.
>> 
>> For use cases where the refresh of an item after update is not necessary, the Session interface is used instead. So, the proposal is...
>> 
>> Move following methods from CmisObject to Session...
>> 
>> ItemIterable<Relationship> Session.getRelationships(ObjectId, boolean, RelationshipDirection, ObjectType, OperationContext)
>> Acl Session.getAcl(ObjectId, boolean)
>> 
>> Add...
>> 
>> ObjectId Session.updateProperties(ObjectId, Map<String, ?>)
>> void applyPolicy(ObjectId, ObjectId...)
>> void removePolicy(ObjectId, ObjectId...)
>> Acl applyAcl(ObjectId, List<Ace> addAces, List<Ace> removeAces, AclPropagation aclPropagation)
>> Acl getAcl(ObjectId, boolean onlyBasicPermissions)
>> 
>> 2) Following the pattern in 1), setting content on a Document alters slightly too.
>> 
>> Document setContentStream(ContentStream contentStream, boolean overwrite)
>> Document deleteContentStream()
>> 
>> Instead of returning ObjectId, the proposal is to return Document. Depending on the repository, the document may be the same item as before (updated in the cache), or a new Document, to represent a new version.
>> 
>> Also add to Session...
>> 
>> ObjectId setContentStream(ObjectId, ContentStream contentStream, boolean overwrite)
>> ObjectId deleteContentStream(ObjectId)
>> 
>> 3) Remove transient methods from Session.
>> 
>> Until we've thought through transient session behaviour I propose we remove the following methods:
>> 
>> Session.save()
>> Session.cancel()
>> 
>> Regards,
>> Dave
> 
> 
> 
> -- 
> Florent Guillaume, Director of R&D, Nuxeo
> Open Source, Java EE based, Enterprise Content Management (ECM)
> http://www.nuxeo.com   http://www.nuxeo.org   +33 1 40 33 79 87


Re: Proposal to clarify CmisObject caching behaviour

Posted by David Caruana <da...@alfresco.com>.
On 12 Oct 2010, at 16:22, Florent Guillaume wrote:

> Hi David,
> 
> I'm a bit confused by some of the vocabulary I must confess. Could we
> make sure we don't confuse the term "cache" and the term "transient
> space", as they have different uses.

Of course.

> 
> So do you want to remove completely any transient space and only have
> methods that write to the remote side on each method call? So, do you
> want to remove the fact that we can do:
>  object.setProperty("foo1", "bar1");
>  object.setProperty("foo2", "bar2");
>  ...
>  object.updateProperties();
> i.e. today there's a mini transient space tied to the properties of
> the object, flushed on updateProperties. I think this is quite useful
> as it avoids having the user building a map by hand and passing it to
> updateProperties, which is ugly for a high-level interface.

Yes, the proposal is to remove the mini transient space. The reason is to simplify behaviour if we were to introduce a CmisObject implementation that always refreshed its cache on updates. For example, with a transient space, what is the behaviour when setProperty has been called and an "update" method is then called prior to updateProperties. Are the transient changes discarded, flushed, or just left as is?

> 
> I'm ok with most methods that can do remote writes returning a CmisObject.
> 
> But I don't like removing convenience methods on CmisObject like
> getRelationships, getAcl, etc. as they provide convenient access to
> the users.

There would still be the methods getRelationships() and getAcl(), but they would only return what has already been cached (as they do today). Currently, there's also getRelationships(boolean, RelationshipDirection, ObjectType, OperationContext) and getAcls(boolean) which go direct to the repository. It's these that I propose are moved to Session.

> 
> OTOH I'm completely for clarifying the caching aspects, for instance
> it's not clear today when caches are invalidated or updated, or what
> happens when you ask for a property that's not in the initial property
> filter that led to the creation of the object (in a number of my unit
> tests in Nuxeo I have to refresh() explicitly but this shouldn't be
> needed when all the writes were mine).

Indeed, this is the confusion I'm trying to remove with this proposal. Admittedly, there is much to discuss, and the proposal is only a starting point, but I wanted to open up the discussion early to determine if this problem is severe enough to tackle.

Regards,
Dave

> 
> Florent
> 
> 
> 
> On Tue, Oct 12, 2010 at 12:49 PM, David Caruana
> <da...@alfresco.com> wrote:
>> Currently, we only have one implementation of Session - PersistentSessionImpl. However, the OpenCMIS client API suggests transient behaviour both in its API definition and behaviour, which I believe can be confusing for users. In particular, when does OpenCMIS read information from the cache vs from the repository, and when does OpenCMIS implicitly update an item in its cache.
>> 
>> I'd like to present the following changes in an attempt to clarify the above and trigger discussion on how to improve things in this area...
>> 
>> 1) All methods on CmisObject operate against the cache. This means that reading a value from an item reads the value from the item in the cache, and updates to the item change the cache i.e. refresh the item in the cache. Methods that read directly from the repository move to Session. So, the proposal is:
>> 
>> Remove the following from CmisObject...
>> CmisObject.setName(String)
>> CmisObject.setProperty(String, Object)
>> CmisObject.updateProperties()
>> 
>> Change CmisObject.updateProperties...
>> CmisObject CmisObject.updateProperties(Map<String, ?>)    (Note: return CmisObject instead of ObjectId)
>> 
>> Note: If the repository creates a new version, a new CmisObject is returned, otherwise the existing CmisObject is refreshed in the cache and returned.
>> 
>> The following 'update' methods are also modified to refresh the item in the cache after update:
>> 
>> void CmisObject.applyPolicy(ObjectId...)    (Note: accept vararg of policy ids)
>> void CmisObject.removePolicy(ObjectId...)   (Note: accept vararg of policy ids)
>> Acl CmisObject.applyAcl(List<Ace>, List<Ace>, AclPropagation)
>> Acl CmisObject.addAcl(List<Ace>, AclPropagation)   (Note: also return Acl to be consistent with applyAcl)
>> Acl CmisObject.removeAcl(List<Ace>, AclPropagation)   (Note: also return Acl to be consistent with applyAcl)
>> 
>> Note: applyPolicy and removePolicy are also changed to accept a vararg of ObjectIds.
>> 
>> For use cases where the refresh of an item after update is not necessary, the Session interface is used instead. So, the proposal is...
>> 
>> Move following methods from CmisObject to Session...
>> 
>> ItemIterable<Relationship> Session.getRelationships(ObjectId, boolean, RelationshipDirection, ObjectType, OperationContext)
>> Acl Session.getAcl(ObjectId, boolean)
>> 
>> Add...
>> 
>> ObjectId Session.updateProperties(ObjectId, Map<String, ?>)
>> void applyPolicy(ObjectId, ObjectId...)
>> void removePolicy(ObjectId, ObjectId...)
>> Acl applyAcl(ObjectId, List<Ace> addAces, List<Ace> removeAces, AclPropagation aclPropagation)
>> Acl getAcl(ObjectId, boolean onlyBasicPermissions)
>> 
>> 2) Following the pattern in 1), setting content on a Document alters slightly too.
>> 
>> Document setContentStream(ContentStream contentStream, boolean overwrite)
>> Document deleteContentStream()
>> 
>> Instead of returning ObjectId, the proposal is to return Document. Depending on the repository, the document may be the same item as before (updated in the cache), or a new Document, to represent a new version.
>> 
>> Also add to Session...
>> 
>> ObjectId setContentStream(ObjectId, ContentStream contentStream, boolean overwrite)
>> ObjectId deleteContentStream(ObjectId)
>> 
>> 3) Remove transient methods from Session.
>> 
>> Until we've thought through transient session behaviour I propose we remove the following methods:
>> 
>> Session.save()
>> Session.cancel()
>> 
>> Regards,
>> Dave
> 
> 
> 
> -- 
> Florent Guillaume, Director of R&D, Nuxeo
> Open Source, Java EE based, Enterprise Content Management (ECM)
> http://www.nuxeo.com   http://www.nuxeo.org   +33 1 40 33 79 87


Re: Proposal to clarify CmisObject caching behaviour

Posted by Florent Guillaume <fg...@nuxeo.com>.
Hi David,

I'm a bit confused by some of the vocabulary I must confess. Could we
make sure we don't confuse the term "cache" and the term "transient
space", as they have different uses.

So do you want to remove completely any transient space and only have
methods that write to the remote side on each method call? So, do you
want to remove the fact that we can do:
  object.setProperty("foo1", "bar1");
  object.setProperty("foo2", "bar2");
  ...
  object.updateProperties();
i.e. today there's a mini transient space tied to the properties of
the object, flushed on updateProperties. I think this is quite useful
as it avoids having the user building a map by hand and passing it to
updateProperties, which is ugly for a high-level interface.

I'm ok with most methods that can do remote writes returning a CmisObject.

But I don't like removing convenience methods on CmisObject like
getRelationships, getAcl, etc. as they provide convenient access to
the users.

OTOH I'm completely for clarifying the caching aspects, for instance
it's not clear today when caches are invalidated or updated, or what
happens when you ask for a property that's not in the initial property
filter that led to the creation of the object (in a number of my unit
tests in Nuxeo I have to refresh() explicitly but this shouldn't be
needed when all the writes were mine).

Florent



On Tue, Oct 12, 2010 at 12:49 PM, David Caruana
<da...@alfresco.com> wrote:
> Currently, we only have one implementation of Session - PersistentSessionImpl. However, the OpenCMIS client API suggests transient behaviour both in its API definition and behaviour, which I believe can be confusing for users. In particular, when does OpenCMIS read information from the cache vs from the repository, and when does OpenCMIS implicitly update an item in its cache.
>
> I'd like to present the following changes in an attempt to clarify the above and trigger discussion on how to improve things in this area...
>
> 1) All methods on CmisObject operate against the cache. This means that reading a value from an item reads the value from the item in the cache, and updates to the item change the cache i.e. refresh the item in the cache. Methods that read directly from the repository move to Session. So, the proposal is:
>
> Remove the following from CmisObject...
> CmisObject.setName(String)
> CmisObject.setProperty(String, Object)
> CmisObject.updateProperties()
>
> Change CmisObject.updateProperties...
> CmisObject CmisObject.updateProperties(Map<String, ?>)    (Note: return CmisObject instead of ObjectId)
>
> Note: If the repository creates a new version, a new CmisObject is returned, otherwise the existing CmisObject is refreshed in the cache and returned.
>
> The following 'update' methods are also modified to refresh the item in the cache after update:
>
> void CmisObject.applyPolicy(ObjectId...)    (Note: accept vararg of policy ids)
> void CmisObject.removePolicy(ObjectId...)   (Note: accept vararg of policy ids)
> Acl CmisObject.applyAcl(List<Ace>, List<Ace>, AclPropagation)
> Acl CmisObject.addAcl(List<Ace>, AclPropagation)   (Note: also return Acl to be consistent with applyAcl)
> Acl CmisObject.removeAcl(List<Ace>, AclPropagation)   (Note: also return Acl to be consistent with applyAcl)
>
> Note: applyPolicy and removePolicy are also changed to accept a vararg of ObjectIds.
>
> For use cases where the refresh of an item after update is not necessary, the Session interface is used instead. So, the proposal is...
>
> Move following methods from CmisObject to Session...
>
> ItemIterable<Relationship> Session.getRelationships(ObjectId, boolean, RelationshipDirection, ObjectType, OperationContext)
> Acl Session.getAcl(ObjectId, boolean)
>
> Add...
>
> ObjectId Session.updateProperties(ObjectId, Map<String, ?>)
> void applyPolicy(ObjectId, ObjectId...)
> void removePolicy(ObjectId, ObjectId...)
> Acl applyAcl(ObjectId, List<Ace> addAces, List<Ace> removeAces, AclPropagation aclPropagation)
> Acl getAcl(ObjectId, boolean onlyBasicPermissions)
>
> 2) Following the pattern in 1), setting content on a Document alters slightly too.
>
> Document setContentStream(ContentStream contentStream, boolean overwrite)
> Document deleteContentStream()
>
> Instead of returning ObjectId, the proposal is to return Document. Depending on the repository, the document may be the same item as before (updated in the cache), or a new Document, to represent a new version.
>
> Also add to Session...
>
> ObjectId setContentStream(ObjectId, ContentStream contentStream, boolean overwrite)
> ObjectId deleteContentStream(ObjectId)
>
> 3) Remove transient methods from Session.
>
> Until we've thought through transient session behaviour I propose we remove the following methods:
>
> Session.save()
> Session.cancel()
>
> Regards,
> Dave



-- 
Florent Guillaume, Director of R&D, Nuxeo
Open Source, Java EE based, Enterprise Content Management (ECM)
http://www.nuxeo.com   http://www.nuxeo.org   +33 1 40 33 79 87