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
<florian.muel...@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
>>>> <florian.muel...@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
>>>>>> <florian.muel...@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
>>>>>>>> <florian.muel...@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
>>>>>>>>>> <stephan.klev...@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

Reply via email to