blob: 76bbc03a1e9833b71e8e5515bd93394da4985aae [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 Zeligsoft (2009) Limited and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.papyrusrt.xtumlrt.util
import java.util.Comparator
import java.util.LinkedHashSet
import java.util.List
import org.eclipse.emf.ecore.EObject
import org.eclipse.papyrusrt.xtumlrt.common.BaseContainer
import org.eclipse.papyrusrt.xtumlrt.common.Behaviour
import org.eclipse.papyrusrt.xtumlrt.common.Capsule
import org.eclipse.papyrusrt.xtumlrt.common.CapsulePart
import org.eclipse.papyrusrt.xtumlrt.common.CommonElement
import org.eclipse.papyrusrt.xtumlrt.common.CommonFactory
import org.eclipse.papyrusrt.xtumlrt.common.Connector
import org.eclipse.papyrusrt.xtumlrt.common.Model
import org.eclipse.papyrusrt.xtumlrt.common.MultiplicityElement
import org.eclipse.papyrusrt.xtumlrt.common.NamedElement
import org.eclipse.papyrusrt.xtumlrt.common.OpaqueExpression
import org.eclipse.papyrusrt.xtumlrt.common.Package
import org.eclipse.papyrusrt.xtumlrt.common.Port
import org.eclipse.papyrusrt.xtumlrt.common.Protocol
import org.eclipse.papyrusrt.xtumlrt.common.ProtocolBehaviourFeatureKind
import org.eclipse.papyrusrt.xtumlrt.common.Signal
import org.eclipse.papyrusrt.xtumlrt.common.StructuredType
import org.eclipse.papyrusrt.xtumlrt.common.ValueSpecification
import org.eclipse.papyrusrt.xtumlrt.common.LiteralNull
import org.eclipse.papyrusrt.xtumlrt.common.LiteralBoolean
import org.eclipse.papyrusrt.xtumlrt.common.LiteralInteger
import org.eclipse.papyrusrt.xtumlrt.common.LiteralReal
import org.eclipse.papyrusrt.xtumlrt.common.LiteralString
import org.eclipse.papyrusrt.xtumlrt.common.LiteralNatural
import org.eclipse.papyrusrt.xtumlrt.common.LiteralUnlimited
import org.eclipse.papyrusrt.xtumlrt.common.EnumerationLiteral
import org.eclipse.papyrusrt.xtumlrt.umlrt.PortKind
import org.eclipse.papyrusrt.xtumlrt.umlrt.PortRegistration
import org.eclipse.papyrusrt.xtumlrt.umlrt.RTPort
import static extension org.eclipse.papyrusrt.xtumlrt.util.GeneralUtil.*
import static extension org.eclipse.papyrusrt.xtumlrt.util.XTUMLRTAnnotations.*
class XTUMLRTUtil
{
static class NameComparator implements Comparator<NamedElement>
{
override int compare( NamedElement o1, NamedElement o2 )
{
// null sorts earlier
if (o1 === null)
return if (o2 === null) 0 else -1
if (o2 === null)
return 1
val name1 = o1.name
val name2 = o2.name
if (name1 === null)
return if (name2 === null) 0 else -1
if (name2 === null)
return 1
return name1.compareTo(name2);
}
}
static def List<CommonElement> getContainerList( CommonElement element )
{
val result = newArrayList
var elem = element
while (elem !== null)
{
result.add(0, elem)
elem = elem.owner
}
result
}
/**
* Returns the owned behaviour of the given capsule if it has one. Otherwise,
* returns any inherited behaviour.
*/
static def Behaviour getActualBehaviour( Capsule capsule )
{
var Behaviour behaviour = null
if (capsule !== null)
{
if (capsule.behaviour !== null)
behaviour = capsule.behaviour
else if (capsule.redefines !== null && capsule.redefines instanceof Capsule)
behaviour = (capsule.redefines as Capsule).actualBehaviour
}
behaviour
}
/**
* Returns the set of all capsules in a model or package.
*/
static def Iterable<Capsule> getAllCapsules( BaseContainer model )
{
val set = new LinkedHashSet<Capsule>()
set.addAll( model.entities.filter( Capsule ) )
for ( pkg : model.packages )
{
set.addAll( pkg.allCapsules )
}
set
}
/**
* Returns the set of all protocols in a model.
*/
static dispatch def Iterable<Protocol> getAllProtocols( Model model )
{
val set = new LinkedHashSet<Protocol>()
set.addAll( model.protocols )
for ( pkg : model.packages )
{
set.addAll( pkg.allProtocols )
}
set
}
/**
* Returns the set of all protocols in a package.
*/
static dispatch def Iterable<Protocol> getAllProtocols( Package packge )
{
val set = new LinkedHashSet<Protocol>()
set.addAll( packge.protocols )
for ( pkg : packge.packages )
{
set.addAll( pkg.allProtocols )
}
set
}
/**
* Returns the set of all parts in the capsule, including those which have been inherited
* and those which are redefinitions of inherited parts.
*/
static def Iterable<CapsulePart> getAllCapsuleParts( Capsule capsule )
{
val allParts = new LinkedHashSet<CapsulePart>()
if (capsule !== null)
{
allParts.addAll( capsule.capsuleParts )
val parentElement = capsule.redefines
if (parentElement !== null && parentElement instanceof Capsule)
{
val parent = parentElement as Capsule
allParts.addAll( parent.allCapsuleParts.filter [ !redefines( capsule, it) ] )
}
}
allParts
}
/**
* Returns the set of all connectors in the capsule, including those which have been inherited
* and those which are redefinitions of inherited connectors.
*/
static def Iterable<Connector> getAllConnectors( Capsule capsule )
{
val allConnectors = new LinkedHashSet<Connector>()
if (capsule !== null)
{
allConnectors.addAll( capsule.capsuleConnectors )
val parentElement = capsule.redefines
if (parentElement !== null && parentElement instanceof Capsule)
{
val parent = parentElement as Capsule
allConnectors.addAll( parent.allConnectors.filter [ !redefines( capsule, it) ] )
}
}
allConnectors
}
/**
* Returns the list of all elements in the containment chain from the root element
* to the given element.
*/
static def Iterable<CommonElement> getAllContainers( CommonElement element )
{
val List<CommonElement> list = newArrayList
var elem = element
while (elem !== null)
{
list.add( 0, elem )
elem = elem.owner
}
list
}
/**
* Returns the set of all ports in the class, including those which have been inherited
* and those which are redefinitions of inherited ports.
*/
static def Iterable<Port> getAllRTPorts( Capsule capsule )
{
val allPorts = new LinkedHashSet<Port>()
if (capsule !== null)
{
allPorts.addAll( capsule.RTPorts )
val parentElement = capsule.redefines
if (parentElement !== null && parentElement instanceof Capsule)
{
val parent = parentElement as Capsule
allPorts.addAll( parent.allRTPorts.filter [ !redefines( capsule, it) ] )
}
}
allPorts
}
/**
* Returns the set of all signals in the protocol, including those which have been inherited
* and those which are redefinitions of inherited signals.
*/
static def Iterable<Signal> getAllSignals( Protocol protocol )
{
val allSignals = new LinkedHashSet<Signal>()
if (protocol !== null)
{
allSignals.addAll( protocol.signals )
val parentElement = protocol.redefines
if (parentElement !== null && parentElement instanceof Capsule)
{
val parent = parentElement as Protocol
allSignals.addAll( parent.allSignals.filter [ !redefines( protocol, it) ] )
}
}
allSignals
}
/**
* Return the given capsule's parts that have a type.
*/
static def Iterable<CapsulePart> getCapsuleParts( Capsule capsule ) {
// Ports are put into a sorted list to make sure that the order is
// stable between
// different parts of the generator (as well as between invocations).
val parts = new LinkedHashSet<CapsulePart>()
parts.addAll( capsule.parts.filter [ type !== null && !isExcluded ] )
parts
}
/**
* Return the given capsule's connectors.
*/
static def Iterable<Connector> getCapsuleConnectors( Capsule capsule ) {
// Connectors are put into a sorted list to make sure that the order is
// stable between
// different parts of the generator (as well as between invocations).
val connectors = new LinkedHashSet<Connector>()
connectors.addAll( capsule.connectors.filter [ !isExcluded ] )
connectors
}
/**
* Return the first container up the containing chain that is a {@link NamedElement}.
*/
static def NamedElement firstNamedContainer(EObject element)
{
if (element === null)
{
null
}
else if (element instanceof NamedElement)
{
element
}
else
{
element.eContainer?.firstNamedContainer
}
}
/**
* Return the first container up the containing chain that is a {@link NamedElement}.
*/
static def NamedElement firstNamespaceContainer(EObject element)
{
if (element === null)
{
null
}
else if (element instanceof NamedElement)
{
if (element.isNamespace)
{
element
}
else
{
element.owner.firstNamespaceContainer
}
}
else
{
element.eContainer?.firstNamespaceContainer
}
}
static def Iterable<Signal> getInSignals( Protocol protocol )
{
protocol.protocolBehaviourFeatures
.filter [ it instanceof Signal && it.kind == ProtocolBehaviourFeatureKind.IN ]
.map [it as Signal]
}
static def Iterable<Signal> getInOutSignals( Protocol protocol )
{
protocol.protocolBehaviourFeatures
.filter [ it instanceof Signal && it.kind == ProtocolBehaviourFeatureKind.INOUT ]
.map [it as Signal]
}
/**
* Returns the lowest common ancestor to the given elements, i.e. the element
* that contains (directly or indirectly) both elements and which doesn't contain any other common
* ancestor of both elements.
*/
static def CommonElement getLowestCommonAncestor( CommonElement element1, CommonElement element2 )
{
val prefix = getLowestCommonAncestorPrefix(element1, element2)
prefix.last
}
/**
* Returns the container list of the lowest common ancestor to the given elements, i.e. the element
* that contains (directly or indirectly) both elements and which doesn't contain any other common
* ancestor of both elements.
*/
static def Iterable<CommonElement> getLowestCommonAncestorPrefix( CommonElement element1, CommonElement element2 )
{
longestCommonPrefix(element1.allContainers, element2.allContainers)
}
static def Iterable<Signal> getOutSignals( Protocol protocol )
{
protocol.protocolBehaviourFeatures
.filter [ it instanceof Signal && it.kind == ProtocolBehaviourFeatureKind.OUT ]
.map [it as Signal]
}
static def NamedElement getOwner( CommonElement element )
{
if (element.eContainer === null) null else element.eContainer as NamedElement
}
static def BaseContainer getRoot( CommonElement element )
{
var elem = element
while ( elem !== null && elem.owner !== null )
elem = elem.owner
if (elem instanceof BaseContainer) elem else null
}
/**
* Returns an iterable over the ports of the given class which redefine some inherited port.
*/
static def Iterable<CapsulePart> getPartRedefinitions( Capsule capsule )
{
capsule.parts.filter[ it.redefines !== null && it.redefines instanceof CapsulePart ]
}
/**
* Returns an iterable over the ports of the given class which redefine some inherited port.
*/
static def Iterable<Port> getPortRedefinitions( Capsule capsule )
{
capsule.ports.filter[ it.redefines !== null && it.redefines instanceof Port ]
}
/**
* Returns an iterable over the connectors of the given class which redefine some inherited connector.
*/
static def Iterable<Connector> getConnectorRedefinitions( Capsule capsule )
{
capsule.connectors.filter[ it.redefines !== null && it.redefines instanceof Connector ]
}
/**
* Returns an iterable over the signals of the given protocol which redefine some inherited signal.
*/
static def Iterable<Signal> getSignalRedefinitions( Protocol protocol )
{
protocol.signals.filter[ it.redefines !== null && it.redefines instanceof Signal ]
}
/**
* Returns an iterable over the ports redefined by the given class.
*/
static def Iterable<CapsulePart> getRedefinedParts( Capsule capsule )
{
capsule.partRedefinitions.map [ it.redefines as CapsulePart ]
}
/**
* Returns an iterable over the ports redefined by the given class.
*/
static def Iterable<Port> getRedefinedPorts( Capsule capsule )
{
capsule.portRedefinitions.map [ it.redefines as Port ]
}
/**
* Returns an iterable over the connectors redefined by the given class.
*/
static def Iterable<Connector> getRedefinedConnectors( Capsule capsule )
{
capsule.connectorRedefinitions.map [ it.redefines as Connector ]
}
/**
* Returns an iterable over the signals redefined by the given protocol.
*/
static def Iterable<Signal> getRedefinedSignals( Protocol protocol )
{
protocol.signalRedefinitions.map [ it.redefines as Signal ]
}
/**
* A filter that produces only Ports that are properly stereotyped as RTPort
* and have a UML-RT protocol.
*/
static def Iterable<Port> getRTPorts( Capsule capsule ) {
// Ports are put into a sorted list to make sure that the order is
// stable between
// different parts of the generator (as well as between invocations).
val ports = new LinkedHashSet<Port>()
ports.addAll( capsule.ports.filter [ type !== null && !isExcluded ] )
ports
}
static def Iterable<StructuredType> getSupertypes( StructuredType type )
{
type.generalizations?.map [ it.getSuper ]
}
static def Iterable<Signal> getSignals( Protocol protocol )
{
protocol.protocolBehaviourFeatures.filter[ it instanceof Signal && !isExcluded ].map [ it as Signal ]
}
static def isExternalPort( Port port )
{
port instanceof RTPort && (port as RTPort).kind == PortKind.EXTERNAL
}
static def isInternalPort( Port port )
{
port instanceof RTPort && (port as RTPort).kind == PortKind.INTERNAL
}
static def isRelayPort( Port port )
{
port instanceof RTPort && (port as RTPort).kind == PortKind.RELAY
}
static def isSAP( Port port )
{
port instanceof RTPort && (port as RTPort).kind == PortKind.SAP
// && ( !(port as RTPort).wired ) && ( !(port as RTPort).publish )
}
static def isSPP( Port port )
{
port instanceof RTPort && (port as RTPort).kind == PortKind.SPP
// && ( !(port as RTPort).wired ) && ( (port as RTPort).publish )
}
static def isWired( Port port )
{
port instanceof RTPort && (port as RTPort).wired
}
/** True if the port should be registered as SAP/SPP at startup or during creation. */
static def isAutomatic( Port port )
{
port instanceof RTPort && (port as RTPort).registration == PortRegistration.AUTOMATIC;
}
/** True if the port is automatic-locked. */
static def isAutomaticLocked( Port port )
{
port instanceof RTPort && (port as RTPort).registration == PortRegistration.AUTOMATICLOCKED;
}
/** True iff the element corresponds to a UML Namespace element. */
static def isNamespace( CommonElement element )
{
element instanceof StructuredType
}
/** True when user requested binding notification. */
static def isNotification( Port port )
{
port instanceof RTPort && (port as RTPort).notification
}
static def isPublish( Port port )
{
port instanceof RTPort && (port as RTPort).publish
}
static def isBorderPort( Port port )
{
port.isExternalPort || port.isRelayPort
}
static def isNonBorderPort( Port port )
{
!port.isBorderPort
// Bug 507005: due to a terminology mismatch, what the runtime calls "internal ports" includes also SAPs and SPPs.
}
/** Return the model-supplied registered name override. */
static def getRegistrationOverride( Port port )
{
if( ! ( port instanceof RTPort ) )
null
else
(port as RTPort).registrationOverride
}
/**
* Return true if the element is replicated and false otherwise.
*/
static def <T extends MultiplicityElement & NamedElement> boolean isReplicated( T element )
{
element.getLowerBound() != 1 || element.getUpperBound() != 1
}
/**
* Return the String value of a given ValueSpecification if it can be computed
*/
static dispatch def String getStringValue( ValueSpecification valSpec )
{
null
}
static dispatch def String getStringValue( LiteralNull valSpec )
{
String.valueOf(null as Object)
}
static dispatch def String getStringValue( LiteralBoolean valSpec )
{
String.valueOf(valSpec.value)
}
static dispatch def String getStringValue( LiteralInteger valSpec )
{
String.valueOf(valSpec.value)
}
static dispatch def String getStringValue( LiteralReal valSpec )
{
String.valueOf(valSpec.value)
}
static dispatch def String getStringValue( LiteralString valSpec )
{
'"' + String.valueOf(valSpec.value) + '"'
}
static dispatch def String getStringValue( LiteralNatural valSpec )
{
String.valueOf(valSpec.value)
}
static dispatch def String getStringValue( LiteralUnlimited valSpec )
{
"*"
}
static dispatch def String getStringValue( OpaqueExpression valSpec )
{
valSpec?.body ?: "0"
}
static dispatch def String getStringValue( EnumerationLiteral valSpec )
{
valSpec.name
}
/**
* Returns true iff the given port is inherited and redefined by the given class.
*/
private static dispatch def redefines( Capsule capsule, Port port )
{
capsule.redefinedPorts.exists[ it == port ]
}
/**
* Returns true iff the given port is inherited and redefined by the given class.
*/
private static dispatch def redefines( Capsule capsule, CapsulePart part )
{
capsule.redefinedParts.exists[ it == part ]
}
/**
* Returns true iff the given connector is inherited and redefined by the given class.
*/
private static dispatch def redefines( Capsule capsule, Connector conn )
{
capsule.redefinedConnectors.exists[ it == conn ]
}
/**
* Returns true iff the given signal is inherited and redefined by the given protocol.
*/
private static dispatch def redefines( Protocol protocol, Signal signal )
{
protocol.redefinedSignals.exists[ it == signal ]
}
static dispatch def getCopy(CommonElement element)
{
null
}
static dispatch def getCopy(LiteralInteger element)
{
CommonFactory.eINSTANCE.createLiteralInteger => [ value = element.value ]
}
static dispatch def getCopy(LiteralNatural element)
{
CommonFactory.eINSTANCE.createLiteralNatural => [ value = element.value ]
}
static dispatch def getCopy(OpaqueExpression element)
{
CommonFactory.eINSTANCE.createOpaqueExpression => [ body = element.body ]
}
/**
* Returns true iff the given element is marked as excluded
*/
static def isExcluded( CommonElement element )
{
val redefinedElementStereotype = getAnnotation( element, "RTRedefinedElement" )
if (redefinedElementStereotype !== null)
{
val rootFragment = getAnnotationProperty( redefinedElementStereotype, "rootFragment" )
if (rootFragment === null)
return true
}
return false
}
}