| /******************************************************************************* |
| * 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 |
| } |
| |
| } |