0

I've got an EMF metamodel as described below:

class Application
  - runsOn: Host [0..*]

interface Host

class VirtualMachine implements Host
  - runsOn: Host [0..*]

class PhysicalMachine implements Host

The question I want to answer using OCL is: find all PhysicalMachines on which a given Application actually runs (directly or transitively). Please note that all of the following paths can occur in the instance model:

- Application runsOn PhysicalServer
- Application runsOn VirtualMachine runsOn PhysicalServer
- Application runsOn VirtualMachine runsOn VirtualMachine runsOn PhysicalServer
- ...

I imagine that this could somehow be expressed using the closure operator of OCL but I can't quite figure out the correct syntax.

Martin Häusler
  • 6,544
  • 8
  • 39
  • 66

1 Answers1

1

After a lot of tinkering, I think I've found an answer.

self.runsOn->asSet()
    ->closure(host: Host | 
        if host.oclIsKindOf(VirtualMachine) then 
            host.oclAsType(VirtualMachine).runsOn 
        else
            host->asSet() 
        endif
    )

This appears to work. Please correct me if the above query is wrong or inefficient.

Edit: Thanks to the comment by Ed Willink below I have simplified the above query to:

self.runsOn->closure(host: Host | host->selectByKind(VirtualMachine).runsOn)
Martin Häusler
  • 6,544
  • 8
  • 39
  • 66
  • The outer - – Ed Willink Dec 16 '17 at 06:58
  • 1
    The outer ->asSet() is probably redundant since Application:runsOn is probably unique. The inner asSet() is inefficient since it invites a recursion to host which has already been accumulated; the only-visit once check ensures that the closure is not infinite; Set{} would be better. If you are after lexical efficiency runsOn->closure(host | host->selectByKind(VirtualMachine).runsOn) is more compact. – Ed Willink Dec 16 '17 at 07:07