OCUP 2 Advanced study materials
OCUP 2 Advanced study resources

Association Ends, Derived Unions and Uniqueness in a Product-Line Model

OCUP 2 Advanced · Put your knowledge to work in context.

All case studies

Association Ends, Derived Unions and Uniqueness in a Product-Line Model

Northwind's product-line model has grown to 700 classes. Orders are modelled as Order with three subclasses (ConfiguredOrder, SpareOrder, ServiceOrder), each holding its lines as owned attributes typed OrderLine. Two problems surfaced. First, a pricing rule must iterate every line of any order through one derived union allItems declared on Order; because lines are plain owned attributes with no association, subsetting cannot be expressed and the union is empty at runtime for the subclasses. Second, the price book must navigate from an OrderLine back to its owning Order; the reverse attribute exists on OrderLine but nothing ties the two attributes together, and the XMI export drops one side on round-trip through a second tool. The team also needs the constraint that no two lines of the same order reference the same product, and it must survive export. The model must stay valid UML 2.5.1 with OCL 2.4, and the repository team refuses profiles or tool-specific tagged values.

1. Explain the difference between an owned attribute and an association member end, why the derived union is empty, and restructure the Order–OrderLine relationship correctly.

Read the worked answer

An owned attribute is a Property owned by the class; on its own it asserts nothing about any other end. A two-way relationship is an Association with two memberEnds; a navigable end owned by the class appears as that class's ownedAttribute and is simultaneously a memberEnd of the association. The association must exist - ownership is a separate question from the relationship.

Why the union is empty:

  • isDerivedUnion on Order::allItems only works if the constituent properties declare subsettedProperty = allItems. Subsetting is a Property-level relationship that is meaningful when the properties are ends of associations along a specialization hierarchy. Two unrelated owned attributes named items in sibling subclasses are not in a subset relationship, so nothing contributes to the union.
  • With no Association there is no opposite end either; the back-pointer attribute on OrderLine is a separate property with no semantic link to the owning end.

Repair:

  1. Create an Association Order–OrderLine with memberEnd order [1] navigable from OrderLine, and memberEnd line [0..*] on Order with isComposite = true and subsettedProperty = Order::allItems.
  2. In each subclass, either inherit that end or declare a narrower end that subsets (and, where the type narrows, redefines) the inherited one, so the union collects the subclass ends.
  3. The XMI now carries one Association with two memberEnds; both navigations and the union are reconstructible, so a second tool cannot independently drop a side.

2. How should the rule "no two lines of one order may reference the same product" be expressed? Compare the OCL invariant with a qualified association and justify the choice.

Read the worked answer

OCL 2.4 invariant on Order:

context Order inv UniqueProducts:
  self.allItems->collect(l : OrderLine | l.product)->isUnique(p | p)

This works once allItems is a proper derived union, because the invariant is written once against the superclass and applies to every subclass. Bind it to the model as a Constraint owned by Order, with the OCL body in the model (not in a document), and both tools must preserve OCL expressions for it to survive export; if one tool does not, mirror it as a named Constraint element and enforce it in the repository validation stage.

Structural alternative: a qualified association Order [1] - qualifier product -> OrderLine [0..1]. That encodes "at most one line per product per order" in the metamodel, so a plain XMI check catches violations without an OCL engine. The cost: the same product may never appear twice even for legitimately split lines (different delivery dates, different warehouses), and quantity and price become properties of the qualified target, so no other key can be used.

Judgement: use the OCL invariant when lines have independent identity and split lines are legal; use the qualifier when product is genuinely the key of the line. Do not do both - a qualifier plus a uniqueness invariant is redundant and the two will diverge after the first refactoring.

3. The second tool's export re-creates Order.line as an owned attribute and drops the association. What model choices reduce that risk, and what should the interchange contract require?

Read the worked answer

UML 2.5.1 permits both ownership patterns (both ends owned by the classes, or one end owned by the association as an ownedEnd), and the serializers differ in which pattern they reconstruct. For cross-tool exchange the safest pattern is asymmetric ownership:

  • One end owned by the class as a navigable ownedAttribute (the direction the price book uses).
  • The other end owned by the Association as an ownedEnd, with the opposite class referencing it only through memberEnd.

This is the pattern most serializers emit and the one they can rebuild from the UML:Association element alone; when both ends are class-owned, some exporters emit only the two UML:Property elements and the association disappears.

Interchange contract items:

  1. Require the Association element with two memberEnd references and the ordered end list; a property that is not listed as a memberEnd is a local attribute, not a relationship.
  2. Require isNavigable, aggregation and subsettedProperty to be preserved, since the union and the price-book navigation depend on them.
  3. Add a round-trip conformance test on a canonical subset of the model (the Order hierarchy plus one association class if any), diffing the computed navigation graph and derived-union membership rather than the raw XMI text.
  4. If a tool cannot preserve the association, treat its export as a lossy projection and forbid it from being the normative interchange path - otherwise the model silently reverts to the current state after every exchange.