Hi,
we have a problem where we must create audit trail of changes made to business objects. Also things should run inside transaction. Our first approach was to create so called command objects from every change but these would be hard to maintain by hand. For example there would be ChangePersonName, ChangeXXXName classes and these would have to be hand created in name: -mehtods. More "clever" approach we come up with is to copy original object and use proxy that records messages send to it and sends them to the copy. Also this proxy creates new proxy when copy returns values. These proxies record message sends to transaction and when transaction is ready these recorded message from all of the proxies are done to the actual objects instead of copies. To create usable copies I found method that (shallow) copies the actual object and its instance variables (Object>>copyTwoLevel). The method is marked to be deprecated soon. Why is that and is there some alternative way of doing this kind of copy? Also if you know some way to trivially handle the audit trail problem I would like to hear... :) -- Panu |
On 4 May 2011 15:02, Panu Suominen <[hidden email]> wrote:
> Hi, > > we have a problem where we must create audit trail of changes made to > business objects. Also things should run inside transaction. Our first > approach was to create so called command objects from every change but > these would be hard to maintain by hand. For example there would be > ChangePersonName, ChangeXXXName classes and these would have to be > hand created in name: -mehtods. More "clever" approach we come up with > is to copy original object and use proxy that records messages send to > it and sends them to the copy. Also this proxy creates new proxy when > copy returns values. These proxies record message sends to transaction > and when transaction is ready these recorded message from all of the > proxies are done to the actual objects instead of copies. > > To create usable copies I found method that (shallow) copies the > actual object and its instance variables (Object>>copyTwoLevel). The > method is marked to be deprecated soon. > Why is that and is there some alternative way of doing this kind of copy? > Also if you know some way to trivially handle the audit trail problem > I would like to hear... :) > > I think that this is too special kind of copy to be provided by default in kernel (so whoever stated that this will be deprecated, i agree with him ;). What you can do is to copy down this method to the root class of your domain hierarchy.. I.e. consider that all your domain objects having single root superclass , like MyDomainObject and then you're free to use this specific kind of copy for your classes, without relying on it in Object protocol. > -- > Panu > -- Best regards, Igor Stasenko AKA sig. |
In reply to this post by Panu Suominen
Hi Panu. I don't know if immutability is available in Pharo, but if it
is it may work for you. You basically mark an object as immutable and register an exception handler. When an immutable object's i.v. is assigned a new value, an exception is raised and the assignment is left pending. There you can log the change and effectively apply the assignment to the object. HTH, Andrés Panu Suominen escribió: > Hi, > > we have a problem where we must create audit trail of changes made to > business objects. Also things should run inside transaction. Our first > approach was to create so called command objects from every change but > these would be hard to maintain by hand. For example there would be > ChangePersonName, ChangeXXXName classes and these would have to be > hand created in name: -mehtods. More "clever" approach we come up with > is to copy original object and use proxy that records messages send to > it and sends them to the copy. Also this proxy creates new proxy when > copy returns values. These proxies record message sends to transaction > and when transaction is ready these recorded message from all of the > proxies are done to the actual objects instead of copies. > > To create usable copies I found method that (shallow) copies the > actual object and its instance variables (Object>>copyTwoLevel). The > method is marked to be deprecated soon. > Why is that and is there some alternative way of doing this kind of copy? > Also if you know some way to trivially handle the audit trail problem > I would like to hear... :) > > |
In reply to this post by Igor Stasenko
On May 4, 2011, at 3:16 PM, Igor Stasenko wrote: > On 4 May 2011 15:02, Panu Suominen <[hidden email]> wrote: >> Hi, >> >> we have a problem where we must create audit trail of changes made to >> business objects. Also things should run inside transaction. Our first >> approach was to create so called command objects from every change but >> these would be hard to maintain by hand. For example there would be >> ChangePersonName, ChangeXXXName classes and these would have to be >> hand created in name: -mehtods. More "clever" approach we come up with >> is to copy original object and use proxy that records messages send to >> it and sends them to the copy. Also this proxy creates new proxy when >> copy returns values. These proxies record message sends to transaction >> and when transaction is ready these recorded message from all of the >> proxies are done to the actual objects instead of copies. mariano got a really nice proxy model based on the stratified proxy of igor (which is in 1.3). >> To create usable copies I found method that (shallow) copies the >> actual object and its instance variables (Object>>copyTwoLevel). The >> method is marked to be deprecated soon. >> Why is that and is there some alternative way of doing this kind of copy? why copy is not enough for you? and you redefine postCopy to copy the instance variables? >> Also if you know some way to trivially handle the audit trail problem >> I would like to hear... :) >> >> > > I think that this is too special kind of copy to be provided by > default in kernel (so whoever stated that this will be deprecated, > i agree with him ;). :) I know that guy. > What you can do is to copy down this method to the root class of your > domain hierarchy.. > I.e. > consider that all your domain objects having single root superclass , > like MyDomainObject > > and then you're free to use this specific kind of copy for your > classes, without relying on it in Object protocol. +1 > >> -- >> Panu >> > > -- > Best regards, > Igor Stasenko AKA sig. > |
On 04 May 2011, at 17:30, Stéphane Ducasse wrote: > > mariano got a really nice proxy model based on the stratified proxy of igor (which is in 1.3). Question: could this be used for PHANtom? We are now using Methodwrappers but there are some issues (fixed in PHANtom). Mariano, Igor, can you explain the advantages of your model wrt methodwrappers? -- Johan Fabry [hidden email] - http://dcc.uchile.cl/~jfabry PLEIAD Lab - Computer Science Department (DCC) - University of Chile |
On 5 May 2011 01:59, Johan Fabry <[hidden email]> wrote:
> > On 04 May 2011, at 17:30, Stéphane Ducasse wrote: > >> >> mariano got a really nice proxy model based on the stratified proxy of igor (which is in 1.3). > > > Question: could this be used for PHANtom? We are now using Methodwrappers but there are some issues (fixed in PHANtom). Mariano, Igor, can you explain the advantages of your model wrt methodwrappers? > Sorry i'm not familiar with methodwrappers. The basic model is separation of proxy and handler. Proxy acts only as a message trap, while handler is actually responsible for handling messages trapped by proxy. Mariano builds on top of that, because he wants to replace classes and/or methods with proxies, and this requires a special handling (class proxy should obey VM-specific Behavior format, and method proxy should implement #run:in:as: when installed in method dictionary ). So, i guess that proxies which representing compiled methods could act similar to method wrappers. But of course you still have to implement all intall/deinstall management et al.. The only advantage of new proxies comparing to usual proxies based on #DNU pattern that they guarantee a clear separation between meta-levels, i.e. even if you send #doesNotUnderstand: message to a proxy, this message will be trapped and handled by handler as any other. -- Best regards, Igor Stasenko AKA sig. |
In reply to this post by Andres Fortier-2
2011/5/4 andres <[hidden email]>:
> Hi Panu. I don't know if immutability is available in Pharo, but if it is it > may work for you. You basically mark an object as immutable and register an > exception handler. When an immutable object's i.v. is assigned a new value, > an exception is raised and the assignment is left pending. There you can log > the change and effectively apply the assignment to the object. This sounds good but it seems that Squeak VM does not yet contain immutable objects. I am not sure. -- Panu |
In reply to this post by Andres Fortier-2
On May 5, 2011, at 8:19 AM, Panu Suominen wrote: > 2011/5/4 andres <[hidden email]>: >> Hi Panu. I don't know if immutability is available in Pharo, but if it is it >> may work for you. You basically mark an object as immutable and register an >> exception handler. When an immutable object's i.v. is assigned a new value, >> an exception is raised and the assignment is left pending. There you can log >> the change and effectively apply the assignment to the object. > > This sounds good but it seems that Squeak VM does not yet contain > immutable objects. > I am not sure. No. They were implemented in the Squeak VM that NewSpeak uses. So the code is out there. Marcus -- Marcus Denker -- http://www.marcusdenker.de INRIA Lille -- Nord Europe. Team RMoD. |
Am 05.05.2011 um 08:24 schrieb Marcus Denker: > > On May 5, 2011, at 8:19 AM, Panu Suominen wrote: > >> 2011/5/4 andres <[hidden email]>: >>> Hi Panu. I don't know if immutability is available in Pharo, but if it is it >>> may work for you. You basically mark an object as immutable and register an >>> exception handler. When an immutable object's i.v. is assigned a new value, >>> an exception is raised and the assignment is left pending. There you can log >>> the change and effectively apply the assignment to the object. >> >> This sounds good but it seems that Squeak VM does not yet contain >> immutable objects. >> I am not sure. > > > No. They were implemented in the Squeak VM that NewSpeak uses. > So the code is out there. > Norbert |
In reply to this post by Stéphane Ducasse
2011/5/5 Stéphane Ducasse <[hidden email]>:
> why copy is not enough for you? > and you redefine postCopy to copy the instance variables? Because it would involve manual labour for any object that is going to be used in business logic. This would create artificial requirement that is easily forgotten. However first try-out of this approach used postCopy in domain objects. I thought that copyTwoLevel is going to be deprecated because it is too specific. However I am not sure whether this is actually true. It depends how often copying objects is necessary. The deprecation is not a problem. I can easily just create utility class that copies objects like copyTwoLevel. -- Panu |
In reply to this post by Igor Stasenko
On Thu, May 5, 2011 at 4:30 AM, Igor Stasenko <[hidden email]> wrote:
Yes, and the cool thing is that proxies can intercept ALL messages, not only those that are not understood. Hence, you don't need to subclass from ProtoObject or nil. In addition (I think, I didn't measure) that they are faster because they don't need to the method lookup until getting to the dnu..but I am not sure about this last one. Another problem with the DNU is what Igor say, you are mixing both things: error handling and message trapping. So...when a proxy receives DNU, how do you know if it was a real dnu or because it needs to trap the message? Implementing method wrappers on top of such proxies is a matter of 5 minutes as much as I can see. In fact, in the paper I "implement" method wrappers as an example. You can take a look by Gofer new squeaksource: 'Marea'; package: 'GhostProxies'; package: 'GhostProxiesTests'; load. But remember it is just a prototype ;) The paper is almost finish... cheers -- Mariano http://marianopeck.wordpress.com |
Ahhh and the difference with MethodWrappers (at least with the implementation that is in the Pharo image)
- MethodWrapper intercepts both things: 1) messages sent to the object (as if it were a compiled method), and 2) method execution MyClass at: #foo put: MyMethodWrapper. (MyClass methodAt: #foo) literals. --->> 1) MyClass new foo ---->> 2) 1) is done using #dnu and 2) using #run:with:in: the problem is that the method wrapper is a subclass from Object, so there are 375 methods (Object methodDict size) that will be understood by the proxy itself instead of trapping the message. Ok, you can subclass from ProtoObject, that would be better (ProtoObject methodDict size -> 38 ). But still, even subclassing from nil, it is not stratified. (MyClass methodAt: #foo) blahBlah will try to trap the message instead of raise a MNU. I don't know what do you need for your case, if both things 1) and 2). If it is only 2) then there is few advantages with our implemetnation. If you need both, then yes, I would take a look. cheers mariano On Thu, May 5, 2011 at 9:59 AM, Mariano Martinez Peck <[hidden email]> wrote:
-- Mariano http://marianopeck.wordpress.com |
In reply to this post by Panu Suominen
On May 5, 2011, at 9:46 AM, Panu Suominen wrote: > 2011/5/5 Stéphane Ducasse <[hidden email]>: >> why copy is not enough for you? >> and you redefine postCopy to copy the instance variables? > > Because it would involve manual labour for any object that is going to > be used in business logic. This would create artificial requirement > that is easily forgotten. However first try-out of this approach used > postCopy in domain objects. > > I thought that copyTwoLevel is going to be deprecated because it is > too specific. However I am not sure whether this is actually true. It > depends how often copying objects is necessary. > The deprecation is not a problem. I can easily just create utility > class that copies objects like copyTwoLevel. why not putting the method in your domain object root? > > -- > Panu > |
2011/5/5 Stéphane Ducasse <[hidden email]>:
> why not putting the method in your domain object root? When doing things like this domain object could return objects out side of the domain object hierarchy and they should be copied. Most notably collections. Also I think that if copyTwoLevel it is too spesific for object it is too spesific for domain objects. That does not matter now because the approach was flawed... Original idea was to copy only two levels to avoid too much work and only do more copying when necessary. Two levels where copied because this would handle situations where objects internal state is changed. More levels would get copied when the proxied object would return new values. Thus the proxy had following code. doesNotUnderstand: aMessage | result | accumulator add: aMessage -> originalObject. result := aMessage sendTo: copyObject. ^ (result isLiteral) ifTrue: [ result ] ifFalse: [ transaction proxyFor: result ] And copyObject is initialized using originalObject copyTwoLevel. However this just is not a proper solution because there might be calls that dive deeply in the structure and alter objects that have not been copied yet (they are lower than second level from object the message is send). But deep copy alone won't handle this either. After deep copying it is hard to say which objects where changed and which were not. -- Panu |
In reply to this post by Mariano Martinez Peck
On 05 May 2011, at 04:10, Mariano Martinez Peck wrote: Ahhh and the difference with MethodWrappers (at least with the implementation that is in the Pharo image) -- Johan Fabry PLEIAD Lab - Computer Science Department (DCC) - University of Chile |
Free forum by Nabble | Edit this page |