| package org.eclipse.papyrus.designer.components.transformation.cpp.xtend |
| |
| import java.util.List |
| import org.eclipse.emf.common.util.BasicEList |
| import org.eclipse.emf.ecore.util.EcoreUtil |
| import org.eclipse.papyrus.designer.components.transformation.component.PrefixConstants |
| import org.eclipse.papyrus.designer.languages.common.base.ElementUtils |
| import org.eclipse.papyrus.designer.transformation.core.transformations.LazyCopier |
| import org.eclipse.papyrus.uml.tools.utils.StereotypeUtil |
| import org.eclipse.uml2.uml.AggregationKind |
| import org.eclipse.uml2.uml.BehavioredClassifier |
| import org.eclipse.uml2.uml.Class |
| import org.eclipse.uml2.uml.ConnectorEnd |
| import org.eclipse.uml2.uml.Interface |
| import org.eclipse.uml2.uml.OpaqueBehavior |
| import org.eclipse.uml2.uml.ParameterDirectionKind |
| import org.eclipse.uml2.uml.Port |
| import org.eclipse.uml2.uml.Property |
| import org.eclipse.uml2.uml.Type |
| import org.eclipse.uml2.uml.UMLPackage |
| import org.eclipse.papyrus.designer.languages.common.profile.Codegen.TemplateBinding |
| import org.eclipse.papyrus.uml.tools.utils.PackageUtil |
| import org.eclipse.papyrus.designer.languages.cpp.library.CppUriConstants |
| |
| /** |
| * Enable ports that delegate to several inner parts/ports, see bug 531771 |
| * |
| * This delegation is bidirectional, i.e. applies to provided and required |
| * ports (methods being called and methods that are calling, respectively) |
| * |
| * For provided ports: return the reference to a broadcast class in the |
| * get_XXX methods. |
| * The user has to verify that the port of the composite has the right |
| * multiplicity. |
| * |
| * For required ports: call all connect_XXX of inner parts in the connect_XXX |
| * of the class that owns inner parts. |
| * |
| * Finally the createConnection method should handle connecting to a port that |
| * returns a vector. In this case we expect the receptacle of the connection |
| * to be of multiplicity several. |
| */ |
| class CreateMultiRefClass { |
| |
| StaticCppToOO cppToOO |
| LazyCopier copier |
| static String progLang = "C++" |
| |
| new(StaticCppToOO cppToOO, LazyCopier copier) { |
| this.cppToOO = cppToOO |
| this.copier = copier |
| } |
| |
| def String createDelegationProvided(Class implementation, List<ConnectorEnd> ces, Port port, String portName, |
| Interface providedIntf) { |
| |
| // We need to create a port representing the delegating port |
| val attributeName = PrefixConstants.attributePrefix + portName |
| |
| var attr = implementation.getOwnedAttribute(attributeName, null) |
| if (attr === null || attr instanceof Port) { |
| val broadcastClass = getOrCreateBroadcastClass(providedIntf) |
| |
| // Create the attribute in implementation for the port and type it with the broadcast class |
| attr = implementation.createOwnedAttribute(attributeName, broadcastClass) |
| attr.setAggregation(AggregationKind.SHARED_LITERAL) |
| |
| // Connect delegated parts (either properties or ports) to the broadcast class |
| return createDelegationConnCode(ces, broadcastClass, portName, providedIntf) |
| } |
| return "" |
| } |
| |
| def String createDelegationConnCode(List<ConnectorEnd> ces, Class broadcastClass, String portName, |
| Interface providedIntf) ''' |
| «val attributeName = PrefixConstants.attributePrefix + portName» |
| // generated broadcast class uses generic port name |
| «val connectOpName = PrefixConstants.connectQ_Prefix + "port"» |
| |
| if («attributeName» == NULL) { |
| «attributeName» = new «broadcastClass.qualifiedName»(); |
| } |
| |
| «FOR ce : ces» |
| «val part = ce.partWithPort» |
| «val role = ce.role» |
| |
| «IF role instanceof Port» |
| «val rolePort = role as Port» |
| «IF rolePort.provideds.contains(providedIntf)» |
| «IF rolePort.provideds.size > 1 || |
| ((rolePort.provideds.size == 1) && !(rolePort.type instanceof Interface))» |
| «IF part.upper > 1» |
| «FOR i : 0 ..< part.upper» |
| «attributeName»->«connectOpName»(«part.name»[«i»].«PrefixConstants.getP_Prefix»«role.name»«providedIntf.name»()); |
| «ENDFOR» |
| «ELSE» |
| «attributeName»->«connectOpName»(«cppToOO.nameRef(part)»«PrefixConstants.getP_Prefix»«role.name»«providedIntf.name»()); |
| «ENDIF» |
| «ELSE» |
| «IF part.upper > 1» |
| «FOR i : 0 ..< part.upper» |
| «attributeName»->«connectOpName»(«part.name»[«i»].«PrefixConstants.getP_Prefix»«role.name»()); |
| «ENDFOR» |
| «ELSE» |
| «attributeName»->«connectOpName»(«cppToOO.nameRef(part)»«PrefixConstants.getP_Prefix»«role.name»()); |
| «ENDIF» |
| «ENDIF» |
| «ENDIF» |
| «ELSE» |
| «IF role instanceof Property» |
| «val roleType = (role as Property).type» |
| «IF roleType instanceof BehavioredClassifier && |
| (roleType as BehavioredClassifier).getInterfaceRealization(null, providedIntf) !== null» |
| «IF (role as Property).upper > 1» |
| «FOR i : 0 ..< (role as Property).upper» |
| «attributeName»->«connectOpName»(«role.name»[«i»]); |
| «ENDFOR» |
| «ELSE» |
| «attributeName»->«connectOpName»(«role.name»); |
| «ENDIF» |
| «ENDIF» |
| «ENDIF» |
| «ENDIF» |
| «ENDFOR» |
| |
| return «attributeName»; |
| ''' |
| |
| def String createDelegationRequired(Class implementation, String portName, Interface requiredIntf) { |
| |
| val attributeName = PrefixConstants.attributePrefix + portName |
| // generated broadcast class uses generic port name |
| val opName = PrefixConstants.connectQ_Prefix + "port" |
| |
| // We need to create a port representing the delegating port |
| var attr = implementation.getOwnedAttribute(attributeName, null) |
| if (attr === null || attr instanceof Port) { |
| |
| val broadcastClass = getOrCreateBroadcastClass(requiredIntf) |
| // Create the attribute in implementation for the port and type it with the broadcast class |
| attr = implementation.createOwnedAttribute(attributeName, broadcastClass) |
| cppToOO.applyRef(attr); |
| // CopyUtils.copyMultElemModifiers(port, attr) |
| // Delegate reference management to broadcastCass |
| return ''' |
| if (!«attributeName») { |
| «attributeName» = new «broadcastClass.qualifiedName»(); |
| } |
| «attributeName»->«opName»(ref); |
| ''' |
| } |
| return ""; |
| } |
| |
| /** |
| * Create a new broadcast class or create an existing |
| */ |
| def Class getOrCreateBroadcastClass(Interface intf) { |
| val broadcastClassName = '''Broadcast_«intf.name»''' |
| var broadcastClass = intf.nearestPackage.getPackagedElement(broadcastClassName) |
| if (broadcastClass instanceof Class) { |
| return broadcastClass as Class |
| } else { |
| return createBroadcastClass(intf) |
| } |
| } |
| |
| /** |
| * Create a broadcast class for a given interface. This class will manage multiple references for the |
| * given interface and provide an API for calling each method of the interface. |
| * The called operation is called for each stored reference. If there is a return value, only the |
| * return value of the last call is returned. |
| */ |
| def Class createBroadcastClass(Interface intf) { |
| // Create the broadcast class |
| // use generic name port, since the implementation is not specific to the port using it |
| val opName = PrefixConstants.connectQ_Prefix + "port" |
| val broadcastClassName = '''Broadcast_«intf.name»''' |
| val broadcastClass = intf.nearestPackage.createOwnedClass(broadcastClassName, false) |
| |
| // Set its interface realization |
| broadcastClass.createInterfaceRealization("broadcast" + intf, intf) |
| |
| // Create the references vector (based on std::vector from STL) |
| PackageUtil.loadPackage(CppUriConstants.STL_LIB, copier.source.eResource.resourceSet) |
| |
| var vector = ElementUtils.getQualifiedElementFromRS(copier.source, PrefixConstants.TYPE_FOR_MULTI_RECEPTACLE) as Type; |
| if (vector !== null) { |
| vector = copier.getCopy(vector); |
| } else { |
| throw new RuntimeException( |
| String.format( |
| "Can not find type %s. Thus, unable to create suitable connect operation in component to OO transformation", |
| PrefixConstants.TYPE_FOR_MULTI_RECEPTACLE)); |
| } |
| var references = broadcastClass.createOwnedAttribute("references", vector) |
| val tBinding = StereotypeUtil.applyApp(references, TemplateBinding) |
| tBinding.actuals.add(cppToOO.createPtrType(intf)) |
| |
| // Create the connect method |
| val connectOperation = broadcastClass.createOwnedOperation(opName, null, null) |
| val connectRefParam = connectOperation.createOwnedParameter("ref", intf) |
| cppToOO.applyRef(connectRefParam) |
| val connectBehavior = broadcastClass.createOwnedBehavior(opName, |
| UMLPackage.eINSTANCE.getOpaqueBehavior()) as OpaqueBehavior |
| connectOperation.getMethods().add(connectBehavior) |
| connectBehavior.getLanguages().add(progLang) |
| connectBehavior.getBodies.add( |
| ''' |
| references.push_back(ref); |
| ''' |
| ) |
| |
| // Create operations of realized interface in broadcast class |
| for (operation : intf.operations) { |
| val parameterNames = new BasicEList<String>(); |
| val parameterTypes = new BasicEList<Type>(); |
| val parameterNamesWithReturn = new BasicEList<String>(); |
| val parameterTypesWithReturn = new BasicEList<Type>(); |
| for (parameter : operation.ownedParameters) { |
| if (parameter.direction != ParameterDirectionKind.RETURN_LITERAL) { |
| parameterNames.add(parameter.name) |
| parameterTypes.add(parameter.type) |
| } |
| parameterNamesWithReturn.add(parameter.name) |
| parameterTypesWithReturn.add(parameter.type) |
| } |
| |
| // Copy operation of interface in class |
| val copiedOperation = EcoreUtil.copy(operation); |
| // val copiedOperation = copier.getCopy(operation); |
| broadcastClass.ownedOperations.add(copiedOperation); |
| var delegationOperation = copiedOperation; |
| |
| // Copy stereotype applications |
| cppToOO.copyCppOperationAndParameterStereotypes(operation, copiedOperation) |
| |
| // Create body |
| var delegateOperationCall = ''' |
| «operation.name»( |
| «FOR parameterName : parameterNames SEPARATOR ", "» |
| «parameterName» |
| «ENDFOR») |
| '''.toString.trim |
| |
| val hasReturn = parameterNamesWithReturn.size > parameterNames.size |
| val delegationOperationBody = ''' |
| for (unsigned int i = 0; i < references.size()«IF hasReturn» - 1«ENDIF»; i++) { |
| references[i]->«delegateOperationCall»; |
| } |
| «IF hasReturn» |
| return references[references.size() - 1]->«delegateOperationCall»; |
| «ENDIF» |
| ''' |
| |
| val delegationOperationBehavior = broadcastClass.createOwnedBehavior(opName, |
| UMLPackage.eINSTANCE.getOpaqueBehavior()) as OpaqueBehavior |
| delegationOperation.getMethods().add(delegationOperationBehavior) |
| |
| delegationOperationBehavior.getLanguages().add(progLang) |
| delegationOperationBehavior.getBodies().add(delegationOperationBody) |
| } |
| return broadcastClass |
| } |
| } |