Search code examples
eclipse-emfemfeclipse-emf-ecore

Bi-directional reference from sub class


Simply put I have the following EMF model:

Step

  • successor
  • predecessor

ForkStep extends Step

  • alternateSuccessor

Now there is a bi-directional reference between the successor and its predecessor - No problem so far.

The tricky part is: How to create a bi-directional reference from alternateSuccessor to its super-class predecessor?

Normally each step can only have one predecessor and one successor. But a fork may have two successors (successor and alternateSuccessor).

If I now go on and create a bi-directional reference, EMF generates a new attribute in the super class, which seems not quite right?


Solution

  • Your question can be understood in two ways:

    1. Given a model, how can we detect which step is "default" and which is "fork".
    2. How can we enforce that users are only able to create "default" steps (single successor) or "fork" steps (multiple successors).

    Case #1:

    You need a single class Step where you introduce a property isForkStep. The value of this property will be derived using OCL as follows: successor->size() > 1.

    First, I created the meta-model (called the file My.ecore) according to your example. I had to add a Scenario class acting as a container for steps. The meta-model looks as follows: enter image description here

    Then, I opened the My.ecore file using "OCLinEcore editor" and added the OCL code to the isForkStep property.

    package test : test = 'test'
    {
        class Scenario {
            property steps : Step[*] { ordered composes };
        }
        class Step {
            attribute stepId : String { id };
            attribute isForkStep : Boolean {
                derivation: successor->size() > 1;
            }
            property predecessor#successor : Step[?];
            property successor#predecessor : Step[*] { ordered };
        }
    }
    

    Then, I tested my new meta-model by creating a "dynamic instance" from Scenario where I created 4 steps. Here is a screenshot from that shows the Scenario instance together with 4 steps. As you can see in the "Properties" view, Step 1 has the property "Is Fork Step" set to true (by clicking to the other steps, you would see false). enter image description here

    Case #2:

    Here, I modeled the situation differently. I created an interface Step and two implementation classes - DefaultStep and ForkStep. Then, I added different OCL constraints to both classes.

    • DefaultStep: successor->size() <= 1
    • ForkStep: successor->size() >= 2

    Note: I might also use successor->size() >= 2 or successor->size() = 0 to allow ForkSteps without successors.

    The meta-model looks like this: enter image description here

    There are many other ways how this can be implemented. For example, you can use Java instead of OCL, or you can model the situation differently.

    Btw. a nice slideshow about OCL in EMF can be found here: http://www.slideshare.net/EdWillink/enriching-withocl