Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF » Re: EMF Derived Attribute Notifier
Re: EMF Derived Attribute Notifier [message #426468] Wed, 07 January 2009 14:22 Go to next message
Eclipse UserFriend
Originally posted by: cdamus.zeligsoft.com

Hi, pvm,

Thanks for the contribution! However, you will get more of your target
audience by posting to the EMF newsgroup, which I have included in my reply.

Cheers,

Christian

pvm wrote:
> If you have a derived attribute in EMF and change one of the attributes
> that the derived value depends on, then no notification will be sent for
> the derived attribute - so it will not change in any editor etc. You
> have to write these yourself.
>
> Here's a class I wrote that I've found useful and perhaps it may be
> useful to others (all comments etc. gratefully received). You can
> specify your derived attribute, and also which other attributes it
> depends on. Listeners are then added as appropriate and when any of your
> dependant attributes change, you'll fire an event for your derived
> attribute.
>
> E.g. You have a Class Library and a set of Books in it. Each Book has a
> pageCount attribute. The Library has a derived attribute totalPageCount
> that adds up all the pages of all the books. Then you can just write...
>
> /**
> * @generated NOT
> */
> protected LibraryImpl() {
> super();
> DerivedAttributeAdapter daa = new DerivedAttributeAdapter(this,
> MyPackage.LIBRARY__TOTALPAGECOUNT);
> daa.addNavigatedDependency(MyPackage.LIBRARY__BOOKS,
> MyPackage.BOOK__PAGECOUNT);
> }
>
> A local dependency is another attribute in the same class. A navigated
> dependency is to an attribute in a class that you have an association
> with. You can add many local dependencies, but only one remote one
> (though it can be a one to many association).
>
> Here it is...
>
> package put.it.where.you.like;
>
> import java.util.ArrayList;
> import java.util.List;
>
> import org.eclipse.emf.common.notify.Notification;
> import org.eclipse.emf.common.notify.impl.AdapterImpl;
> import org.eclipse.emf.ecore.EObject;
> import org.eclipse.emf.ecore.impl.ENotificationImpl;
> import org.eclipse.emf.ecore.impl.EObjectImpl;
>
> public class DerivedAttributeAdapter extends AdapterImpl {
> private final EObjectImpl source;
> private final int derivedFeature;
>
> private List<Integer> localFeatures = new ArrayList<Integer>();
>
> // TODO this lot could be put into a subclass and put in a list to
> allow for
> // multiple navigated dependencies
> private int dependantFeature = Notification.NO_FEATURE_ID;
> private Class<?> dependantClass = null;
> private int navigationFeature = Notification.NO_FEATURE_ID;
>
> private AdapterImpl dependantAdapter = new AdapterImpl() {
>
> @Override
> public void notifyChanged(Notification msg) {
>
> if (msg.getFeatureID(dependantClass) == dependantFeature &&
> msg.getEventType() == Notification.SET) {
> notifyDerivedAttributeChange();
> }
> }
> };
>
> /*
> * Convenience constructor for a local and navigated dependency
> */
> public DerivedAttributeAdapter(EObjectImpl source, int
> derivedFeature, int navigationFeature, int dependantFeature, int
> localFeature) {
> this(source, derivedFeature);
> addNavigatedDependency(navigationFeature, dependantFeature);
> addLocalDependency(localFeature);
> }
>
> /*
> * Convenience constructor for a navigated dependency
> */
> public DerivedAttributeAdapter(EObjectImpl source, int
> derivedFeature, int navigationFeature, int dependantFeature) {
> this(source, derivedFeature);
> addNavigatedDependency(navigationFeature, dependantFeature);
> }
>
> /*
> * Convenience constructor for a local dependency
> */
> public DerivedAttributeAdapter(EObjectImpl source, int
> derivedFeature, int localFeature) {
> this(source, derivedFeature);
> addLocalDependency(localFeature);
> }
>
> public DerivedAttributeAdapter(EObjectImpl source, int
> derivedFeature) {
> super();
> this.source = source;
> this.derivedFeature = derivedFeature;
> source.eAdapters().add(this);
> }
>
> public void addNavigatedDependency(int navigationFeature, int
> dependantFeature) {
> this.dependantFeature = dependantFeature;
> this.navigationFeature = navigationFeature;
> this.dependantClass =
> source.eClass().getEStructuralFeature(navigationFeature).get EType().getInstanceClass();
>
> }
>
> public void addLocalDependency(int localFeature) {
> localFeatures.add(localFeature);
> }
>
> @Override
> public void notifyChanged(Notification notification) {
> if (notification.getFeatureID(source.getClass()) ==
> navigationFeature) {
> switch (notification.getEventType()) {
> // TODO support ADD_MANY/REMOVE_MANY?
> case Notification.ADD:
> EObject added = (EObject) notification.getNewValue();
> added.eAdapters().add(dependantAdapter);
> break;
> case Notification.SET:
> EObject newValue = (EObject) notification.getNewValue();
> EObject oldValue = (EObject) notification.getOldValue();
> if (oldValue != null)
> oldValue.eAdapters().remove(dependantAdapter);
> if (newValue != null)
> newValue.eAdapters().add(dependantAdapter);
> break;
> case Notification.REMOVE:
> EObject removed = (EObject) notification.getOldValue();
> removed.eAdapters().remove(dependantAdapter);
> break;
> default:
> return; // No notification
> }
> notifyDerivedAttributeChange();
> } else if
> (localFeatures.contains(notification.getFeatureID(source.get Class()))) {
> if (notification.getEventType() == Notification.SET) {
> notifyDerivedAttributeChange();
> }
> }
> }
>
> private void notifyDerivedAttributeChange() {
> if (source.eNotificationRequired()) {
> source.eNotify(new ENotificationImpl(source,
> Notification.SET, derivedFeature, null, source.eGet(
> derivedFeature, true, true)));
> }
> }
>
> }
>
>
Re: EMF Derived Attribute Notifier [message #426470 is a reply to message #426468] Wed, 07 January 2009 15:21 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33140
Registered: July 2009
Senior Member
This is a multi-part message in MIME format.
--------------040707080001020101050909
Content-Type: text/plain; charset=ISO-8859-15; format=flowed
Content-Transfer-Encoding: 7bit

Guys,

I keep wondering about the most general way to do this...

One interesting approach that Boris Bokowski explained to me is if you
have something like read "notification" (as in
https://bugs.eclipse.org/bugs/show_bug.cgi?id=247130) you could
automatically add listeners to all the objects that are accessed while
the derived attribute is being computed. Of course this requires so
global setup---an access listener attached to all objects in the
resource set as well as easy hookup into that global listener---but it
would work for any derivation pattern...

There's also the work underway in
https://bugs.eclipse.org/bugs/show_bug.cgi?id=216701 for specifying a
derived feature's behavior declaratively. This would seem potentially a
good place to try to fit in the design below.

I'll comment specifically on the text below.


Christian W. Damus wrote:
> Hi, pvm,
>
> Thanks for the contribution!
Yes, they're always a good thing. :-)
> However, you will get more of your target audience by posting to the
> EMF newsgroup, which I have included in my reply.
>
> Cheers,
>
> Christian
>
> pvm wrote:
>> If you have a derived attribute in EMF and change one of the
>> attributes that the derived value depends on, then no notification
>> will be sent for the derived attribute - so it will not change in any
>> editor etc. You have to write these yourself.
>>
>> Here's a class I wrote that I've found useful and perhaps it may be
>> useful to others (all comments etc. gratefully received). You can
>> specify your derived attribute, and also which other attributes it
>> depends on. Listeners are then added as appropriate and when any of
>> your dependant attributes change, you'll fire an event for your
>> derived attribute.
A great way to contribute is to write an EMF Recipe for others to follow
and post to the newsgroup to announce you've done that so people will
tend to find it and provide feedback quickly:

http://wiki.eclipse.org/EMF/Recipes

>>
>> E.g. You have a Class Library and a set of Books in it. Each Book has
>> a pageCount attribute. The Library has a derived attribute
>> totalPageCount that adds up all the pages of all the books. Then you
>> can just write...
>>
>> /**
>> * @generated NOT
>> */
>> protected LibraryImpl() {
>> super();
>> DerivedAttributeAdapter daa = new DerivedAttributeAdapter(this,
>> MyPackage.LIBRARY__TOTALPAGECOUNT);
>> daa.addNavigatedDependency(MyPackage.LIBRARY__BOOKS,
>> MyPackage.BOOK__PAGECOUNT);
>> }
Note that an interesting alternative to create an adapter and adding it
to the list is to make your objects "self adapting." I.e., you can
specialize eNotificationRequired to always return true so that when
there are changes eNotify will always be called, even if there are no
adapters listening. Then you can specialize eNotify (remembering to
call super!) just like you specialize the notifyChanged method of the
adapter. It saves quite a bit of space. I see your implementation is
nicely encapsulated and reusable as an adapter though...
>>
>> A local dependency is another attribute in the same class. A
>> navigated dependency is to an attribute in a class that you have an
>> association with. You can add many local dependencies, but only one
>> remote one (though it can be a one to many association).
>>
>> Here it is...
>>
>> package put.it.where.you.like;
>>
>> import java.util.ArrayList;
>> import java.util.List;
>>
>> import org.eclipse.emf.common.notify.Notification;
>> import org.eclipse.emf.common.notify.impl.AdapterImpl;
>> import org.eclipse.emf.ecore.EObject;
>> import org.eclipse.emf.ecore.impl.ENotificationImpl;
>> import org.eclipse.emf.ecore.impl.EObjectImpl;
>>
>> public class DerivedAttributeAdapter extends AdapterImpl {
>> private final EObjectImpl source;
You should generally refer to EObjectImpl only in the extends of a
derived class and no where else. Use EObject or InternalEObject for all
other purposes. After all, other implementation classes can directly
extend BasicEObjectImpl, MinimalEObjectImpl from
https://bugs.eclipse.org/bugs/show_bug.cgi?id=252501 is such an example.
>> private final int derivedFeature;
>>
>> private List<Integer> localFeatures = new ArrayList<Integer>();
>>
>> // TODO this lot could be put into a subclass and put in a list
>> to allow for
>> // multiple navigated dependencies
>> private int dependantFeature = Notification.NO_FEATURE_ID;
>> private Class<?> dependantClass = null;
>> private int navigationFeature = Notification.NO_FEATURE_ID;
>>
>> private AdapterImpl dependantAdapter = new AdapterImpl() {
>>
>> @Override
>> public void notifyChanged(Notification msg) {
>>
>> if (msg.getFeatureID(dependantClass) == dependantFeature
It might be better to use getFeature and then you only need to record an
EStructuralFeature object to compare it to (which you can get via
XyzPackage.Literals.<class-name>__<feature-name>)
>> && msg.getEventType() == Notification.SET) {
The second test is cheaper than the first test, so is likely to be more
efficient to have it first.
>> notifyDerivedAttributeChange();
>> }
>> }
>> };
>>
>> /*
>> * Convenience constructor for a local and navigated dependency
>> */
>> public DerivedAttributeAdapter(EObjectImpl source, int
>> derivedFeature, int navigationFeature, int dependantFeature, int
>> localFeature) {
>> this(source, derivedFeature);
>> addNavigatedDependency(navigationFeature, dependantFeature);
>> addLocalDependency(localFeature);
>> }
>>
>> /*
>> * Convenience constructor for a navigated dependency
>> */
>> public DerivedAttributeAdapter(EObjectImpl source, int
>> derivedFeature, int navigationFeature, int dependantFeature) {
>> this(source, derivedFeature);
>> addNavigatedDependency(navigationFeature, dependantFeature);
>> }
>>
>> /*
>> * Convenience constructor for a local dependency
>> */
>> public DerivedAttributeAdapter(EObjectImpl source, int
>> derivedFeature, int localFeature) {
>> this(source, derivedFeature);
>> addLocalDependency(localFeature);
>> }
>>
>> public DerivedAttributeAdapter(EObjectImpl source, int
>> derivedFeature) {
>> super();
>> this.source = source;
>> this.derivedFeature = derivedFeature;
>> source.eAdapters().add(this);
>> }
>>
>> public void addNavigatedDependency(int navigationFeature, int
>> dependantFeature) {
>> this.dependantFeature = dependantFeature;
>> this.navigationFeature = navigationFeature;
>> this.dependantClass =
>> source.eClass().getEStructuralFeature(navigationFeature).get EType().getInstanceClass();
>>
Definitely it looks like working with EStructuralFeature instances would
be safer and simpler than with feature IDs. (Feature IDs are great for
efficient dispatch but they're kind of error prone because of multiple
inheritance; people assume the same feature ID will work in a derive
class, which is a bad assumption.)
>> }
>>
>> public void addLocalDependency(int localFeature) {
>> localFeatures.add(localFeature);
>> }
>>
>> @Override
>> public void notifyChanged(Notification notification) {
>> if (notification.getFeatureID(source.getClass()) ==
>> navigationFeature) {
Again a dangerous use of feature IDs. It really should be
source.eClass().getInstanceClass()..
>> switch (notification.getEventType()) {
>> // TODO support ADD_MANY/REMOVE_MANY?
EContentAdapter is a good place to snarf logic.
>> case Notification.ADD:
>> EObject added = (EObject) notification.getNewValue();
>> added.eAdapters().add(dependantAdapter);
>> break;
>> case Notification.SET:
>> EObject newValue = (EObject) notification.getNewValue();
>> EObject oldValue = (EObject) notification.getOldValue();
>> if (oldValue != null)
>> oldValue.eAdapters().remove(dependantAdapter);
>> if (newValue != null)
>> newValue.eAdapters().add(dependantAdapter);
>> break;
>> case Notification.REMOVE:
>> EObject removed = (EObject) notification.getOldValue();
>> removed.eAdapters().remove(dependantAdapter);
>> break;
>> default:
>> return; // No notification
>> }
>> notifyDerivedAttributeChange();
>> } else if
>> (localFeatures.contains(notification.getFeatureID(source.get Class()))) {
>> if (notification.getEventType() == Notification.SET) {
>> notifyDerivedAttributeChange();
>> }
>> }
>> }
>>
>> private void notifyDerivedAttributeChange() {
>> if (source.eNotificationRequired()) {
>> source.eNotify(new ENotificationImpl(source,
>> Notification.SET, derivedFeature, null, source.eGet(
>> derivedFeature, true, true)));
A callback to the LibraryImpl that computes the value might be good.
Some issues that jump to mind are what happens while the model is being
read it. We'd be recomputing the total page count a great many
times... Once each time a book is added as it is deserialized, and then
again each time the number of pages is set. And of course no one is
listening or caring about the value at this point... I could imagine
not hooking up the logic (adapter) until the first time the derived
attribute is computed...

I think this is a great start for a new recipe! Thanks!!
>> }
>> }
>>
>> }
>>
>>

--------------040707080001020101050909
Content-Type: text/html; charset=ISO-8859-15
Content-Transfer-Encoding: 8bit

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html;charset=ISO-8859-15"
http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
Guys,<br>
<br>
I keep wondering about the most general way to do this...<br>
<br>
One interesting approach that Boris Bokowski explained to me is if you
have something like read "notification" (as in <a
href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=247130">https://bugs.eclipse.org/bugs/show_bug.cgi?id=247130</a>)
you could automatically add listeners to all the objects that are
accessed while the derived attribute is being computed.


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: EMF Derived Attribute Notifier [message #426472 is a reply to message #426470] Wed, 07 January 2009 15:55 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: cdamus.zeligsoft.com

Hi, Ed,

What is the status of 216701? I am hoping to be able to show it off at
EclipseCon, and it wbn if it weren't patchware by then ;-)

cW


Ed Merks wrote:
> Guys,
>
> I keep wondering about the most general way to do this...
>
> One interesting approach that Boris Bokowski explained to me is if you
> have something like read "notification" (as in
> https://bugs.eclipse.org/bugs/show_bug.cgi?id=247130) you could
> automatically add listeners to all the objects that are accessed while
> the derived attribute is being computed. Of course this requires so
> global setup---an access listener attached to all objects in the
> resource set as well as easy hookup into that global listener---but it
> would work for any derivation pattern...
>
> There's also the work underway in
> https://bugs.eclipse.org/bugs/show_bug.cgi?id=216701 for specifying a
> derived feature's behavior declaratively. This would seem potentially a
> good place to try to fit in the design below.
>
> I'll comment specifically on the text below.

-----8<-----
Re: EMF Derived Attribute Notifier [message #426473 is a reply to message #426472] Wed, 07 January 2009 16:54 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33140
Registered: July 2009
Senior Member
Christian,

It's a little stalled. Too many irons in the fire and too many trips to
the hospital... :-(

I got caught up in the minimal EObject footprint thing and Kenn seemed
less frantic about those association link things. Hopefully I can start
making progress on it soon. Unless of course Eike and Kenn start
jumping up and down about the access listeners. I'm easily swayed
others... :-P


Christian W. Damus wrote:
> Hi, Ed,
>
> What is the status of 216701? I am hoping to be able to show it off
> at EclipseCon, and it wbn if it weren't patchware by then ;-)
>
> cW
>
>
> Ed Merks wrote:
>> Guys,
>>
>> I keep wondering about the most general way to do this...
>>
>> One interesting approach that Boris Bokowski explained to me is if
>> you have something like read "notification" (as in
>> https://bugs.eclipse.org/bugs/show_bug.cgi?id=247130) you could
>> automatically add listeners to all the objects that are accessed
>> while the derived attribute is being computed. Of course this
>> requires so global setup---an access listener attached to all objects
>> in the resource set as well as easy hookup into that global
>> listener---but it would work for any derivation pattern...
>>
>> There's also the work underway in
>> https://bugs.eclipse.org/bugs/show_bug.cgi?id=216701 for specifying a
>> derived feature's behavior declaratively. This would seem
>> potentially a good place to try to fit in the design below.
>>
>> I'll comment specifically on the text below.
>
> -----8<-----


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: EMF Derived Attribute Notifier [message #426474 is a reply to message #426473] Wed, 07 January 2009 17:44 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: cdamus.zeligsoft.com

Thanks, Ed.

Don't worry, I don't mean to add pressure! I should probably pitch in
more, myself, but you know ... ;-)

cW


Ed Merks wrote:
> Christian,
>
> It's a little stalled. Too many irons in the fire and too many trips to
> the hospital... :-(
>
> I got caught up in the minimal EObject footprint thing and Kenn seemed
> less frantic about those association link things. Hopefully I can start
> making progress on it soon. Unless of course Eike and Kenn start
> jumping up and down about the access listeners. I'm easily swayed
> others... :-P
>
>
> Christian W. Damus wrote:
>> Hi, Ed,
>>
>> What is the status of 216701? I am hoping to be able to show it off
>> at EclipseCon, and it wbn if it weren't patchware by then ;-)
>>
>> cW

-----8<-----
Re: EMF Derived Attribute Notifier [message #426480 is a reply to message #426474] Wed, 07 January 2009 20:02 Go to previous messageGo to next message
Eike Stepper is currently offline Eike StepperFriend
Messages: 6682
Registered: July 2009
Senior Member
Christian W. Damus schrieb:
> Thanks, Ed.
>
> Don't worry, I don't mean to add pressure!
So I'll do it :P

I think it's a fundamental enhancement and for orthogonal technologies
like the CDO Model Repository it's certainly of great value!

Cheers
/Eike

----
http://thegordian.blogspot.com


> I should probably pitch in more, myself, but you know ... ;-)
>
> cW
>
>
> Ed Merks wrote:
>> Christian,
>>
>> It's a little stalled. Too many irons in the fire and too many trips
>> to the hospital... :-(
>>
>> I got caught up in the minimal EObject footprint thing and Kenn
>> seemed less frantic about those association link things. Hopefully I
>> can start making progress on it soon. Unless of course Eike and Kenn
>> start jumping up and down about the access listeners. I'm easily
>> swayed others... :-P
>>
>>
>> Christian W. Damus wrote:
>>> Hi, Ed,
>>>
>>> What is the status of 216701? I am hoping to be able to show it off
>>> at EclipseCon, and it wbn if it weren't patchware by then ;-)
>>>
>>> cW
>
> -----8<-----


Re: EMF Derived Attribute Notifier [message #426497 is a reply to message #426480] Thu, 08 January 2009 13:31 Go to previous messageGo to next message
Sven Efftinge is currently offline Sven EfftingeFriend
Messages: 1823
Registered: July 2009
Senior Member
> I think it's a fundamental enhancement and for orthogonal technologies
> like the CDO Model Repository it's certainly of great value!

https://bugs.eclipse.org/bugs/show_bug.cgi?id=247130 is much more
important! :-)

Cheers,
Sven
Re: EMF Derived Attribute Notifier [message #426501 is a reply to message #426497] Thu, 08 January 2009 16:02 Go to previous messageGo to next message
Eike Stepper is currently offline Eike StepperFriend
Messages: 6682
Registered: July 2009
Senior Member
Sven Efftinge schrieb:
>> I think it's a fundamental enhancement and for orthogonal
>> technologies like the CDO Model Repository it's certainly of great
>> value!
>
> https://bugs.eclipse.org/bugs/show_bug.cgi?id=247130 is much more
> important! :-)
Must have been confused! I meant this bug ;-)

Cheers
/Eike

----
http://thegordian.blogspot.com


Re: EMF Derived Attribute Notifier [message #426502 is a reply to message #426501] Thu, 08 January 2009 16:23 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33140
Registered: July 2009
Senior Member
Guys,

It's good when I'm swayed in one general direction. With the EObject
foot print work just about done and with the pattern that's reusable to
minimize the footprint impact of access listeners (to effectively zero
when they aren't used), it's ready to be visited yet again...


Eike Stepper wrote:
> Sven Efftinge schrieb:
>>> I think it's a fundamental enhancement and for orthogonal
>>> technologies like the CDO Model Repository it's certainly of great
>>> value!
>>
>> https://bugs.eclipse.org/bugs/show_bug.cgi?id=247130 is much more
>> important! :-)
> Must have been confused! I meant this bug ;-)
>
> Cheers
> /Eike
>
> ----
> http://thegordian.blogspot.com
>


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: EMF Derived Attribute Notifier [message #426503 is a reply to message #426502] Thu, 08 January 2009 18:35 Go to previous message
Eike Stepper is currently offline Eike StepperFriend
Messages: 6682
Registered: July 2009
Senior Member
Ed Merks schrieb:
> Guys,
>
> It's good when I'm swayed in one general direction. With the EObject
> foot print work just about done and with the pattern that's reusable
> to minimize the footprint impact of access listeners (to effectively
> zero when they aren't used), it's ready to be visited yet again...
Hurray! ;-)

>
>
> Eike Stepper wrote:
>> Sven Efftinge schrieb:
>>>> I think it's a fundamental enhancement and for orthogonal
>>>> technologies like the CDO Model Repository it's certainly of great
>>>> value!
>>>
>>> https://bugs.eclipse.org/bugs/show_bug.cgi?id=247130 is much more
>>> important! :-)
>> Must have been confused! I meant this bug ;-)
>>
>> Cheers
>> /Eike
>>
>> ----
>> http://thegordian.blogspot.com
>>


Previous Topic:diagnostic
Next Topic:reflection: accessing UML classes from (instance) EObject?
Goto Forum:
  


Current Time: Thu Apr 25 11:04:57 GMT 2024

Powered by FUDForum. Page generated in 0.04873 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top