如何从 QVTo 中的生命线获取一组有序的发生规范?
How to get an OrderedSet of OccurrenceSpecifications from a Lifeline in QVTo?
根据 UML spec 第 570 页的图表,我得出结论,Lifeline
应该有 events
属性,持有 OrderedSet(OcurrenceSpecification)
。不幸的是,它不存在,至少在我使用的 QVTo 实现中是这样。
我只有 coveredBy
属性,为我提供(无序)Set(InteractionFragment)
。由于我的转换依赖于 MessageOcurrenceSpecification
的正确顺序,因此我需要以某种方式自己实现我期望由缺失的 events
属性.
实现的内容
这是我目前拥有的:
helper Lifeline::getEvents (): OrderedSet(OccurrenceSpecification) {
return self.coveredBy->selectByKind(OccurrenceSpecification)->sortedBy(true);
}
显然 sortedBy(true)
并没有让我走得太远,但我不知道更多。谁能帮忙?
到目前为止,我所能找到的都是几年前其他人为同样的问题而苦苦挣扎,但没有解决方案:
不知道可不可以,直接用coveredBy
得到一个有序的集合。由于 coveredBy
是无序的,如果您直接通过该功能访问它,您将获得不可预测的顺序,如果您尝试使用 eGet(...)
访问它,则会出现相同的结果。
但是,如果我理解正确的话,有一个 "trick" 可以工作。
它依赖于这样的假设,即您需要的每个 OccurrenceSpecification
实例都由包含 Lifeline
的同一个 Interaction
持有,并使用 EMF 存储包含元素的方式。实际上,每个包含的元素相对于其父元素总是有点 'ordered'(对于每个集合,因此当使用集合中的元素位置表示 XMI 引用时,EMF 可以找到元素)。因此,我们的想法是访问拥有生命线的 Interaction
包含的所有元素,并过滤 coveredBy
中包含的元素。
用 Acceleo 表达
这在MTL/Acceleo中很容易写。知道您不使用它,但它说明了表达式的作用:
# In Acceleo:
# 'self' is the lifeline instance
self.interaction.eAllContents(OccurrenceSpecification)->select(e | self.coveredBy->includes(e))->asOrderedSet()
使用 self.interaction
检索 Interaction
,然后使用 eAllContents(...)
获取所有包含的元素,然后过滤 self.coveredBy
集合中的元素。
但在 QVT 中不太直观,因为 eAllContents(...)
不存在。相反,您必须访问在 EObject
和 returns 上定义的 eContents()
和 EList
,后者被转换为 Sequence
(在 QVT 中,eAllContents()
returns a ETreeIterator
未被 QVT 引擎转换)。
那么,如何在助手中获得对eContents()
的访问权限呢?有两种解决方案:
解决方案 1:使用 emf.tools
库
emf.tools
库使您能够使用 asEObject()
将您的对象转换为纯 EObject
并为您提供更多访问方法(如 eClass()
例如...等)。
import emf.tools; -- we import the EMF tools library
modeltype UML ...; -- all your metamodel imports and stuffs
...
helper Lifeline::getEvents (): OrderedSet(OccurrenceSpecification) {
return self.interaction.asEObject().eContents()[OccurrenceSpecification]->select(e | self.coveredBy->includes(e))->asOrderedSet();
}
解决方案 2:使用 oclAstype(...)
如果由于某种原因无法访问 emf.tools
,您仍然可以使用 oclAsType(...)
.
转换为 EObject
modeltype UML ...; -- all your metamodel imports and stuffs
modeltype ECORE "strict" uses ecore('http://www.eclipse.org/emf/2002/Ecore'); -- you also register the Ecore metamodel
...
helper Lifeline::getEvents (): OrderedSet(OccurrenceSpecification) {
return self.interaction.oclAsType(EObject).eContents()[OccurrenceSpecification]->select(e | self.coveredBy->includes(e))->asOrderedSet();
}
限制
好吧,老实说,这个解决方案似乎适用于我执行的快速测试,但我不能 100% 确定你会拥有你想要的所有元素,因为这段代码依赖于强有力的假设您需要的每个 OccurrenceSpecification
都在与 Liteline
实例相同的 Interaction
中。如果您确定您需要的所有 coveredBy
元素都在 Interaction
中(我认为它们应该是),那么,这不是最性感的解决方案,但它应该可以完成工作。
编辑>
hielsnoppe 提出的 比我这里介绍的更优雅,应该优先考虑。
基于 并结合我一位同事的意见,我为 QVTo 提出了以下解决方案:
-- -----------------------------------------------------------------------------
-- Polyfill for the missing Lifeline::events property
query Lifeline::getEvents (): OrderedSet(OccurrenceSpecification) {
return self.interaction.fragment
->selectByKind(OccurrenceSpecification)
->select(os: OccurrenceSpecification | os.covered->includes(self))
->asOrderedSet();
}
你是对的。 Lifeline::events 属性 清楚地显示在图表上并出现在派生模型中,例如 UML.merged.uml.
不幸的是,Eclipse QVTo 使用 UML 元模型的 Ecore 投影到 UML.ecore,其中修剪了无法导航的对立面。 (最近的 UML2Ecore 增强功能允许名称作为 EAnnotation 保留。)但是,一旦真正的 属性 名称 "events" 被修剪,隐式 属性 名称 "OccurrenceSpecification" 应该可以工作。
所有关联在 OCL 中都可以双向导航,所以这个损失是一个错误。 (新的基于 Pivot 的 Eclipse OCL 返回到主要的 UML 模型以避免 UML2Ecore 损失。一旦 Eclipse QVTo 迁移到 Pivot OCL,您应该会看到您预期的行为。)
根据 UML spec 第 570 页的图表,我得出结论,Lifeline
应该有 events
属性,持有 OrderedSet(OcurrenceSpecification)
。不幸的是,它不存在,至少在我使用的 QVTo 实现中是这样。
我只有 coveredBy
属性,为我提供(无序)Set(InteractionFragment)
。由于我的转换依赖于 MessageOcurrenceSpecification
的正确顺序,因此我需要以某种方式自己实现我期望由缺失的 events
属性.
这是我目前拥有的:
helper Lifeline::getEvents (): OrderedSet(OccurrenceSpecification) {
return self.coveredBy->selectByKind(OccurrenceSpecification)->sortedBy(true);
}
显然 sortedBy(true)
并没有让我走得太远,但我不知道更多。谁能帮忙?
到目前为止,我所能找到的都是几年前其他人为同样的问题而苦苦挣扎,但没有解决方案:
不知道可不可以,直接用coveredBy
得到一个有序的集合。由于 coveredBy
是无序的,如果您直接通过该功能访问它,您将获得不可预测的顺序,如果您尝试使用 eGet(...)
访问它,则会出现相同的结果。
但是,如果我理解正确的话,有一个 "trick" 可以工作。
它依赖于这样的假设,即您需要的每个 OccurrenceSpecification
实例都由包含 Lifeline
的同一个 Interaction
持有,并使用 EMF 存储包含元素的方式。实际上,每个包含的元素相对于其父元素总是有点 'ordered'(对于每个集合,因此当使用集合中的元素位置表示 XMI 引用时,EMF 可以找到元素)。因此,我们的想法是访问拥有生命线的 Interaction
包含的所有元素,并过滤 coveredBy
中包含的元素。
用 Acceleo 表达
这在MTL/Acceleo中很容易写。知道您不使用它,但它说明了表达式的作用:
# In Acceleo:
# 'self' is the lifeline instance
self.interaction.eAllContents(OccurrenceSpecification)->select(e | self.coveredBy->includes(e))->asOrderedSet()
使用 self.interaction
检索 Interaction
,然后使用 eAllContents(...)
获取所有包含的元素,然后过滤 self.coveredBy
集合中的元素。
但在 QVT 中不太直观,因为 eAllContents(...)
不存在。相反,您必须访问在 EObject
和 returns 上定义的 eContents()
和 EList
,后者被转换为 Sequence
(在 QVT 中,eAllContents()
returns a ETreeIterator
未被 QVT 引擎转换)。
那么,如何在助手中获得对eContents()
的访问权限呢?有两种解决方案:
解决方案 1:使用 emf.tools
库
emf.tools
库使您能够使用 asEObject()
将您的对象转换为纯 EObject
并为您提供更多访问方法(如 eClass()
例如...等)。
import emf.tools; -- we import the EMF tools library
modeltype UML ...; -- all your metamodel imports and stuffs
...
helper Lifeline::getEvents (): OrderedSet(OccurrenceSpecification) {
return self.interaction.asEObject().eContents()[OccurrenceSpecification]->select(e | self.coveredBy->includes(e))->asOrderedSet();
}
解决方案 2:使用 oclAstype(...)
如果由于某种原因无法访问 emf.tools
,您仍然可以使用 oclAsType(...)
.
EObject
modeltype UML ...; -- all your metamodel imports and stuffs
modeltype ECORE "strict" uses ecore('http://www.eclipse.org/emf/2002/Ecore'); -- you also register the Ecore metamodel
...
helper Lifeline::getEvents (): OrderedSet(OccurrenceSpecification) {
return self.interaction.oclAsType(EObject).eContents()[OccurrenceSpecification]->select(e | self.coveredBy->includes(e))->asOrderedSet();
}
限制
好吧,老实说,这个解决方案似乎适用于我执行的快速测试,但我不能 100% 确定你会拥有你想要的所有元素,因为这段代码依赖于强有力的假设您需要的每个 OccurrenceSpecification
都在与 Liteline
实例相同的 Interaction
中。如果您确定您需要的所有 coveredBy
元素都在 Interaction
中(我认为它们应该是),那么,这不是最性感的解决方案,但它应该可以完成工作。
编辑>
hielsnoppe 提出的
基于
-- -----------------------------------------------------------------------------
-- Polyfill for the missing Lifeline::events property
query Lifeline::getEvents (): OrderedSet(OccurrenceSpecification) {
return self.interaction.fragment
->selectByKind(OccurrenceSpecification)
->select(os: OccurrenceSpecification | os.covered->includes(self))
->asOrderedSet();
}
你是对的。 Lifeline::events 属性 清楚地显示在图表上并出现在派生模型中,例如 UML.merged.uml.
不幸的是,Eclipse QVTo 使用 UML 元模型的 Ecore 投影到 UML.ecore,其中修剪了无法导航的对立面。 (最近的 UML2Ecore 增强功能允许名称作为 EAnnotation 保留。)但是,一旦真正的 属性 名称 "events" 被修剪,隐式 属性 名称 "OccurrenceSpecification" 应该可以工作。
所有关联在 OCL 中都可以双向导航,所以这个损失是一个错误。 (新的基于 Pivot 的 Eclipse OCL 返回到主要的 UML 模型以避免 UML2Ecore 损失。一旦 Eclipse QVTo 迁移到 Pivot OCL,您应该会看到您预期的行为。)