This blog post is the 2nd in a series of posts detailing some concepts for a generic framework for the support of splitables. For this concept we will include the term “slice”. A “slice” is one of the partial model elements that together form the merged splitables.
Effects of being splittable
If an model element (EObject) is splitable / has a splitable feature, this has two kinds of impacts:
- Impact on the “behavior” of the class itself.
- Impact on other classes, that have features of a splitable type
Impact on the Class ITSELF
- any feature call on such an object needs to join the features of all this objects’ slices. This includes primitive and more complex features.
IMPACT ON OTHER CLASSES
- By Feature: any feature call on another class’ feature, that could contain a splittable object, needs to filter the result of the feature to return a result, where the slices are merged.
This affects the entire model, all classes could be affected, since all could have a feature of a splitable type.
This affects any features that are a super-class of a splittable object.
- By containment/aggregation: If a class is splittable, then all possible classes in all containment trees that lead to a splittable class must also be splittable. Otherwise it would not really be possible to create a spittable tree, since the splittable element could be only in one file when the containment hierarchy is not splittable.
- By inheritance: That also implies, that if a class gains “splittable” through this containment rule, all of it’s subclasses must be splittable too, since it could be that they have the specific instance of the containment feature.
Components of a splittable tooling
- ISplitKeyProvider: For a given object, identifies a “key” that is used to identify slices that constitute an splitable. E.g., this could be the fully qualified name.
- ISliceFinder: Given an object, finds all object that constitute that splittable.
- ISplittingConfiguration: Given an object or structural features, decides if that is splittable.
- IPrimarySliceFinder: Given an object, finds the object that represents the joined splitable.
- IFeatureCalculator: Create a joint view of the splittables
- Arbiter: Decide where to put new elements / how to move elements
For an object, returns the key that is used to identifiy the slices that together make up a model. In a simple implementation, this could e.g. be the fully qualified name. For some AUTOSAR elements, this is the FQN plus additional variant information.
In a simple implementation, all the slices can be identified through their key and the slice finder finds all objects with the same key. In more advanced implementation, caching by key.
Primary Slice Finder
Returns an object, that represents the fusioned object given a specific key. That could be a new object, in case a model is copied. Or, if we inject behavior with AspectJ, one of the slices that is used. Important: Must always be unique, i.e. for a given split key, this must _always_ return the same object.
Must be able to create a joint view of all the slices. Can be e.g. on copy when creating a shadow model, it could also be dynamic, creating a common view e.g. with AspectJ.
Joining Structural Features
- For references / containment, that could contain a splittable, only return the PrimarySlice within the feature.
- 0..1: Intercept call and replace with PrimarySlice
- 0..n: Return new list that replaces contents with primary slice
- Primitives / All objects with 0..1 multiplicity (including references, containment)
- Return value when all slices have the same value or 0
- Throw exception otherwise (merge conflict)
- Needs a list implementation that delegates the contents of the original list. Should always return the same list –> Feature Calculator is responsible. Could maintain own cache or add a new value by means of AspectJ