Bug 561617 - [C++ CodeGen] Generated connections do not reflect the model for multiple delegation

- Don't use index attributes in case of multiple delegations (unify and simplify behavior)
- Use the same broadcast class for provided and required case. As this case only depends on the
  required interface, place this class into the nearest package of this interface instead of
  the nearest package of the component.
- Always use a std::vector for reference list instead of relying on ListHint, otherwise the list
  related code would break depending on used hint (difference to 1st patch proposition)
- Refactor code (additional class CreateMultiRefClass)

Change-Id: I88214c8daedd6cac44a436247ceca6b04f7156d9
Signed-off-by: Ansgar Radermacher <ansgar.radermacher@cea.fr>
diff --git a/plugins/components/org.eclipse.papyrus.designer.components.modellibs.core/src/org/eclipse/papyrus/designer/components/modellibs/core/transformations/AbstractCompToOO.xtend b/plugins/components/org.eclipse.papyrus.designer.components.modellibs.core/src/org/eclipse/papyrus/designer/components/modellibs/core/transformations/AbstractCompToOO.xtend
index 0f7b9c7..497dfea 100644
--- a/plugins/components/org.eclipse.papyrus.designer.components.modellibs.core/src/org/eclipse/papyrus/designer/components/modellibs/core/transformations/AbstractCompToOO.xtend
+++ b/plugins/components/org.eclipse.papyrus.designer.components.modellibs.core/src/org/eclipse/papyrus/designer/components/modellibs/core/transformations/AbstractCompToOO.xtend
@@ -249,23 +249,6 @@
 		} else {
 			var op = implementation.createOwnedOperation(opName, null, null)
 			val boolean multiPort = (portInfo.getUpper() > 1) || (portInfo.getUpper() == -1) // -1 indicates "*"
-			if (multiPort) {
-
-				// add index parameter
-				var eLong = ElementUtils.getQualifiedElementFromRS(copier.source,
-					PrefixConstants.INDEX_TYPE_FOR_MULTI_RECEPTACLE)
-				if (eLong !== null) {
-					eLong = copier.getCopy(eLong);
-				}
-				if (eLong instanceof Type) {
-					op.createOwnedParameter("index", eLong)
-				} else {
-					throw new RuntimeException(
-						String.format(
-							"Can not find type %s. Thus, unable to create suitable connect operation in component to OO transformation",
-							PrefixConstants.INDEX_TYPE_FOR_MULTI_RECEPTACLE))
-				}
-			}
 			val refParam = op.createOwnedParameter("ref", requiredIntf)
 			applyRef(refParam)
 
@@ -296,14 +279,7 @@
 								targetOpName += requiredIntf.name
 							}
 							
-							body = '''«part.nameRef»«targetOpName»'''
-		
-							// TODO: no check that multiplicity of both port matches
-							if ((portInfo.getUpper() > 1) || (portInfo.getUpper() == -1)) {
-								body += "(index, ref);"
-							} else {
-								body += "(ref);"
-							}
+							body = '''«part.nameRef»«targetOpName»(ref);'''
 						}
 					} else {
 						if (part.type instanceof Classifier
@@ -389,12 +365,12 @@
 					val EList<PortInfo> subPorts = PortUtils.flattenExtendedPort(port)
 					for (PortInfo subPort : subPorts) {
 						cmd += '''  // realization of connection for sub-port «subPort.port.name»''' + NL
-						cmd += connectPorts(indexMap, connector, end1, end2, subPort.port)
-						cmd += connectPorts(indexMap, connector, end2, end1, subPort.port)
+						cmd += connectPorts(connector, end1, end2, subPort.port)
+						cmd += connectPorts(connector, end2, end1, subPort.port)
 					}
 				} else {
-					cmd += connectPorts(indexMap, connector, end1, end2, null)
-					cmd += connectPorts(indexMap, connector, end2, end1, null)
+					cmd += connectPorts(connector, end1, end2, null)
+					cmd += connectPorts(connector, end2, end1, null)
 				}
 				createConnBody += cmd + NL
 			}
@@ -430,7 +406,7 @@
 	 * @return
 	 * @throws TransformationException
 	 */
-	def connectPorts(Map<MultiplicityElement, Integer> indexMap, Connector connector, ConnectorEnd receptacleEnd,
+	def connectPorts(Connector connector, ConnectorEnd receptacleEnd,
 		ConnectorEnd facetEnd, Port subPort) throws TransformationException {
 		val association = connector.type
 		if ((receptacleEnd.role instanceof Port) && (facetEnd.role instanceof Port)) {
@@ -445,7 +421,6 @@
 
 				var subPortName = ""
 				if(subPort !== null) subPortName += "_" + subPort.name
-				val indexName = getIndexName(indexMap, receptaclePort, receptacleEnd)
 				
 				var result = ""
 				
@@ -464,7 +439,7 @@
 						if (!facetPortName.empty) {
 							val setter = '''«receptaclePart.nameRef»connect_«receptaclePortName»«subPortName»'''
 							val getter = '''«facetPart.nameRef»get_«facetPortName»«subPortName»()'''
-							result += '''«setter»(«indexName»«getter»);''' + NL
+							result += '''«setter»(«getter»);''' + NL
 						}
 					}
 				} else { // receptaclePort requires only 1 interface
@@ -479,7 +454,7 @@
 					if (!facetPortName.empty) {
 						val setter = '''«receptaclePart.nameRef»connect_«receptaclePort.name»«subPortName»'''
 						val getter = '''«facetPart.nameRef»get_«facetPortName»«subPortName»()'''
-						result += '''«setter»(«indexName»«getter»);''' + NL
+						result += '''«setter»(«getter»);''' + NL
 					}
 				}
 				
@@ -493,7 +468,6 @@
 				val facetPart = facetEnd.role as Property
 				val receptaclePart = facetEnd.partWithPort
 
-				val indexName = getIndexName(indexMap, receptaclePort, receptacleEnd)
 				var result = ""
 				
 				if (receptaclePort.getRequireds().size > 1) { // receptaclePort requires several interfaces
@@ -502,12 +476,12 @@
 						
 						val setter = '''«receptaclePart.nameRef»connect_«receptaclePortName»'''
 						val getter = '''«facetPart.getRef»'''
-						result += '''«setter»(«indexName»«getter»);''' + NL
+						result += '''«setter»(«getter»);''' + NL
 					}
 				} else {
 					val setter = '''«receptaclePart.nameRef»connect_«receptaclePort.name»'''
 					val getter = '''«facetPart.getRef»'''
-					result += '''«setter»(«indexName»«getter»);''' + NL
+					result += '''«setter»(«getter»);''' + NL
 				}
 				
 				return result
@@ -552,16 +526,6 @@
 			if ((assocProp1 !== null) && assocProp1.isNavigable) {
 				var setter = '''«receptaclePart.name».«assocProp1.name»'''
 				val getter = '''«facetPart.name»'''
-				if (assocProp1.upper != 1) {
-					// handle association ends with multiplicty != 1, use same map as for ports
-					var indexValue = indexMap.get(assocProp1)
-					if (indexValue === null) {
-						indexValue = new Integer(0)
-						indexMap.put(assocProp1, indexValue)
-					}
-					setter += '''[«indexValue++»]'''
-					indexMap.put(assocProp1, indexValue)
-				}
 				return '''«setter» = «getter»;''' + NL
 			}
 
@@ -575,35 +539,6 @@
 	}
 
 	/**
-	 * Handle ports with multiplicity > 1. The idea is that we could have
-	 * multiple connections targeting a receptacle. The first connection would
-	 * start with index 0. Implementations can make no assumption which
-	 * connection is associated with a certain index. [want to avoid associative
-	 * array in runtime].
-	 * 
-	 * @param port
-	 * @param end
-	 * @return
-	 */
-	static def getIndexName(Map<MultiplicityElement, Integer> indexMap, Port port, ConnectorEnd end) {
-		if ((port.getUpper() > 1) || (port.getUpper() == -1)) {
-
-			// index depends of combination of property and port, use connector
-			// end as key
-			var indexValue = indexMap.get(end)
-			if (indexValue === null) {
-				indexValue = 0
-				indexMap.put(end, indexValue)
-			}
-			var index = indexValue + ", "
-			indexValue++
-			indexMap.put(end, indexValue)
-			return index
-		}
-		return ""
-	}
-
-	/**
 	 * Return true, if the bootloader is responsible for the instantiation of a
 	 * part.
 	 * 
@@ -675,64 +610,4 @@
 
 		return false
 	}
-	
-	/**
-	 * Returns true if the port delegates to multiple parts/ports. Checks in depth.
-	 * @param port
-	 * @return port has multiple delegations in depth
-	 */
-	def void getAllConnectedProviders(Port port, Interface requiredInterface, List<Property> connectedProviders, List<Connector> visitedConnectors) {
-		for (element : port.model.allOwnedElements) {
-			if (element instanceof Connector) {
-				val connector = element as Connector
-				if (!visitedConnectors.contains(connector)) {
-					visitedConnectors.add(connector)
-
-					if (connector.ends.size == 2) {
-						var ConnectorEnd otherEnd = null
-						if (connector.ends.get(0).role == port) {
-							otherEnd = connector.ends.get(1)
-						} else if (connector.ends.get(1).role == port) {
-							otherEnd = connector.ends.get(0)
-						}
-						
-						if (otherEnd !== null) {
-							if (otherEnd.role instanceof Port) {
-								val otherEndPort = otherEnd.role as Port
-								if (otherEndPort.provideds.contains(requiredInterface)) {
-									if (otherEnd.partWithPort !== null && !connectedProviders.contains(otherEnd.partWithPort)) {
-										if (otherEnd.partWithPort.upper > 0) {
-											for (var i = 0; i < otherEnd.partWithPort.upper; i++) {
-												connectedProviders.add(otherEnd.partWithPort)
-											}
-										} else {
-											connectedProviders.add(otherEnd.partWithPort)
-										}
-									}
-								} else if (otherEndPort.requireds.contains(requiredInterface)) {
-									getAllConnectedProviders(otherEndPort, requiredInterface, connectedProviders, visitedConnectors)
-								}
-							} else if (otherEnd.role instanceof Property) {
-								val otherEndPart = otherEnd.role as Property
-								if (otherEndPart.type instanceof Class) {
-									val otherEndClass = otherEndPart.type as Class
-									if (otherEndClass.implementedInterfaces.contains(requiredInterface)) {
-										if (!connectedProviders.contains(otherEndPart)) {
-											if (otherEndPart.upper > 0) {
-												for (var i = 0; i < otherEndPart.upper; i++) {
-													connectedProviders.add(otherEndPart)
-												}
-											} else {
-												connectedProviders.add(otherEndPart)
-											}
-										}
-									}
-								} 
-							}
-						}
-					}
-				}				
-			}
-		}
-	}
 }
diff --git a/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/META-INF/MANIFEST.MF b/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/META-INF/MANIFEST.MF
index b85d525..07c3e71 100644
--- a/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/META-INF/MANIFEST.MF
+++ b/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/META-INF/MANIFEST.MF
@@ -16,7 +16,8 @@
  org.eclipse.papyrus.designer.components.modellibs.core;bundle-version="0.8.0",
  org.eclipse.papyrus.designer.languages.common.base;bundle-version="1.1.0",
  org.eclipse.uml2.uml.profile.standard;bundle-version="1.0.0",
- org.eclipse.papyrus.designer.languages.common.profile;bundle-version="1.1.0"
+ org.eclipse.papyrus.designer.languages.common.profile;bundle-version="1.1.0",
+ org.eclipse.papyrus.designer.languages.cpp.library;bundle-version="1.1.0"
 Bundle-Vendor: %providerName
 Bundle-ActivationPolicy: lazy
 Bundle-Version: 0.8.1.qualifier
diff --git a/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/src/org/eclipse/papyrus/designer/components/transformation/cpp/xtend/CreateMultiRefClass.xtend b/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/src/org/eclipse/papyrus/designer/components/transformation/cpp/xtend/CreateMultiRefClass.xtend
new file mode 100644
index 0000000..d2a713f
--- /dev/null
+++ b/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/src/org/eclipse/papyrus/designer/components/transformation/cpp/xtend/CreateMultiRefClass.xtend
@@ -0,0 +1,266 @@
+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
+	}
+}
diff --git a/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/src/org/eclipse/papyrus/designer/components/transformation/cpp/xtend/DynamicCppToOO.xtend b/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/src/org/eclipse/papyrus/designer/components/transformation/cpp/xtend/DynamicCppToOO.xtend
index e5a98aa..c2490d0 100644
--- a/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/src/org/eclipse/papyrus/designer/components/transformation/cpp/xtend/DynamicCppToOO.xtend
+++ b/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/src/org/eclipse/papyrus/designer/components/transformation/cpp/xtend/DynamicCppToOO.xtend
@@ -15,40 +15,41 @@
  *****************************************************************************/
 package org.eclipse.papyrus.designer.components.transformation.cpp.xtend
 
-import org.eclipse.papyrus.designer.components.transformation.extensions.IOOTrafo
-import org.eclipse.papyrus.designer.transformation.core.transformations.LazyCopier
-import org.eclipse.uml2.uml.Class
-import org.eclipse.uml2.uml.Property
-import org.eclipse.uml2.uml.Port
-import org.eclipse.papyrus.uml.tools.utils.StereotypeUtil
-import org.eclipse.uml2.uml.AggregationKind
-import org.eclipse.uml2.uml.UMLPackage
-import org.eclipse.uml2.uml.OpaqueBehavior
-import org.eclipse.uml2.uml.ConnectorEnd
-import org.eclipse.papyrus.uml.tools.utils.ConnectorUtil
-import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Ptr
-import org.eclipse.uml2.uml.Type
 import java.util.HashMap
 import java.util.Map
-import org.eclipse.uml2.uml.Connector
 import org.eclipse.emf.common.util.EList
-import org.eclipse.papyrus.designer.components.transformation.cpp.Messages
-import static extension org.eclipse.papyrus.designer.components.transformation.cpp.xtend.CppUtils.nameRef;
-import org.eclipse.papyrus.uml.tools.utils.PackageUtil
-import org.eclipse.papyrus.designer.components.transformation.PortUtils
+import org.eclipse.papyrus.designer.components.modellibs.core.transformations.Constants
 import org.eclipse.papyrus.designer.components.transformation.PortInfo
-import org.eclipse.papyrus.designer.transformation.base.utils.TransformationException
-import org.eclipse.papyrus.designer.transformation.base.utils.CopyUtils
+import org.eclipse.papyrus.designer.components.transformation.PortUtils
 import org.eclipse.papyrus.designer.components.transformation.component.PrefixConstants
 import org.eclipse.papyrus.designer.components.transformation.component.PrefixConstants.CIFvariant
-import org.eclipse.papyrus.designer.components.modellibs.core.transformations.Constants
+import org.eclipse.papyrus.designer.components.transformation.cpp.Messages
+import org.eclipse.papyrus.designer.components.transformation.extensions.IOOTrafo
 import org.eclipse.papyrus.designer.languages.common.base.ElementUtils
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Ptr
+import org.eclipse.papyrus.designer.transformation.base.utils.CopyUtils
 import org.eclipse.papyrus.designer.transformation.base.utils.PartsUtil
+import org.eclipse.papyrus.designer.transformation.base.utils.TransformationException
+import org.eclipse.papyrus.designer.transformation.core.transformations.LazyCopier
+import org.eclipse.papyrus.uml.tools.utils.ConnectorUtil
+import org.eclipse.papyrus.uml.tools.utils.StereotypeUtil
+import org.eclipse.uml2.uml.AggregationKind
+import org.eclipse.uml2.uml.Class
+import org.eclipse.uml2.uml.Connector
+import org.eclipse.uml2.uml.ConnectorEnd
+import org.eclipse.uml2.uml.OpaqueBehavior
+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 static extension org.eclipse.papyrus.designer.components.transformation.cpp.xtend.CppUtils.nameRef
 
 /**
  * This class realizes the dynamic variant of the OO-transformation
  * 
  * TODO: currently not tested/used, needs to be aligned with abstract transformation
+ *       In does currently not support multiple references, as the static variant
  */
 class DynamicCppToOO implements IOOTrafo {
 
@@ -193,20 +194,7 @@
 					// ports, we may have to do that.
 				} else {
 					var op = implementation.createOwnedOperation(opName, null, null)
-					val boolean multiPort = (portInfo.getUpper() > 1) || (portInfo.getUpper() == -1) // -1 indicates "*"
-					if (multiPort) {
 
-						// add index parameter
-						val eLong = ElementUtils.getQualifiedElementFromRS(PackageUtil.getRootPackage(implementation),
-							PrefixConstants.INDEX_TYPE_FOR_MULTI_RECEPTACLE)
-						if (eLong instanceof Type) {
-							op.createOwnedParameter("index", eLong) 
-						} else {
-							throw new RuntimeException(
-								String.format(Messages.CompImplTrafos_CannotFindType,
-									PrefixConstants.INDEX_TYPE_FOR_MULTI_RECEPTACLE))
-						}
-					}
 					val refParam = op.createOwnedParameter("ref", requiredIntf) 
 					StereotypeUtil.apply(refParam, Ptr)
 
@@ -227,15 +215,7 @@
 						if (role instanceof Port) {
 							// in case of a delegation, use name of target port which might be different
 							val targetOpName = PrefixConstants.connectQ_Prefix + role.name
-							body = '''«part.nameRef»«targetOpName»'''
-
-							// TODO: no check that multiplicity of both port matches
-							if ((portInfo.getUpper() > 1) || (portInfo.getUpper() == -1)) {
-								body += "(index, ref);";
-							}
-							else {
-								body += "(ref);";
-							}
+							body = '''«part.nameRef»«targetOpName»(ref)'''
 
 						} else {
 							// TODO: does this case make sense?
@@ -253,7 +233,6 @@
 							attr.setAggregation(AggregationKind.SHARED_LITERAL)
 						}
 						body = attributeName
-						if(multiPort) body += "[index]"
 						body += " = ref;"
 					}
 
diff --git a/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/src/org/eclipse/papyrus/designer/components/transformation/cpp/xtend/StaticCppToOO.xtend b/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/src/org/eclipse/papyrus/designer/components/transformation/cpp/xtend/StaticCppToOO.xtend
index f9331f7..1dd06e9 100644
--- a/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/src/org/eclipse/papyrus/designer/components/transformation/cpp/xtend/StaticCppToOO.xtend
+++ b/plugins/components/org.eclipse.papyrus.designer.components.transformation.cpp/src/org/eclipse/papyrus/designer/components/transformation/cpp/xtend/StaticCppToOO.xtend
@@ -6,7 +6,7 @@
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
  * https://www.eclipse.org/legal/epl-2.0/
- *
+ * 
  * SPDX-License-Identifier: EPL-2.0
  * 
  * Contributors:
@@ -18,17 +18,13 @@
  *****************************************************************************/
 package org.eclipse.papyrus.designer.components.transformation.cpp.xtend
 
-import java.util.Map
-import org.eclipse.emf.common.util.BasicEList
-import org.eclipse.emf.common.util.UniqueEList
-import org.eclipse.emf.ecore.util.EcoreUtil
 import org.eclipse.papyrus.designer.components.modellibs.core.transformations.AbstractCompToOO
 import org.eclipse.papyrus.designer.components.modellibs.core.transformations.Constants
 import org.eclipse.papyrus.designer.components.transformation.PortInfo
 import org.eclipse.papyrus.designer.components.transformation.PortUtils
 import org.eclipse.papyrus.designer.components.transformation.component.PrefixConstants
 import org.eclipse.papyrus.designer.components.transformation.extensions.IOOTrafo
-import org.eclipse.papyrus.designer.languages.common.base.ElementUtils
+import org.eclipse.papyrus.designer.languages.common.profile.Codegen.NoCodeGen
 import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Array
 import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Const
 import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.ConstInit
@@ -36,6 +32,7 @@
 import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Inline
 import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Ptr
 import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Ref
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Typedef
 import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Variadic
 import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Virtual
 import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Volatile
@@ -53,19 +50,15 @@
 import org.eclipse.uml2.uml.ConnectorEnd
 import org.eclipse.uml2.uml.Element
 import org.eclipse.uml2.uml.Interface
-import org.eclipse.uml2.uml.MultiplicityElement
 import org.eclipse.uml2.uml.OpaqueBehavior
 import org.eclipse.uml2.uml.Operation
-import org.eclipse.uml2.uml.Package
 import org.eclipse.uml2.uml.Parameter
-import org.eclipse.uml2.uml.ParameterDirectionKind
 import org.eclipse.uml2.uml.Port
+import org.eclipse.uml2.uml.PrimitiveType
 import org.eclipse.uml2.uml.Property
-import org.eclipse.uml2.uml.Type
 import org.eclipse.uml2.uml.UMLPackage
-import org.eclipse.uml2.uml.profile.standard.Create
 import org.eclipse.uml2.uml.util.UMLUtil
-import org.eclipse.papyrus.designer.languages.common.profile.Codegen.NoCodeGen
+import org.eclipse.uml2.uml.Type
 
 /**
  * This class realizes the transformation from component-based to object-oriented
@@ -80,11 +73,39 @@
 	override nameRef(Property attribute) {
 		CppUtils.nameRef(attribute)
 	}
-	
+
+	/**
+	 * Apply a pointer to the (typed) element
+	 */
 	override applyRef(Element element) {
 		StereotypeUtil.apply(element, Ptr)
 	}
 
+	/**
+	 * Create a ptr_type for the given typed element
+	 * This is required, in order to create a vector of pointers
+	 * instead of a pointer towards a vector
+	 */
+	def createPtrType(Type type) {
+		// check, if an "_ptr" type already exists
+		if (!type.name.endsWith("_ptr")) {
+			val pkg = type.nearestPackage
+			val name = type.name + "_ptr"
+			var ptrType = pkg.getPackagedElement(name) as PrimitiveType
+			if (ptrType === null) {
+				ptrType = pkg.createOwnedPrimitiveType(name)
+				val typedef = StereotypeUtil.applyApp(ptrType, Typedef)
+				// dependencies do not work for primitive types, as a
+				// workaround, prefix typedef with class (ok for pointer types)
+				typedef.definition = '''class «type.name» *'''
+			}
+			return ptrType;
+		}
+		else {
+			return type;
+		}
+	}
+
 	override getRef(Property attribute) {
 		CppUtils.getRef(attribute)
 	}
@@ -114,7 +135,7 @@
 			}
 		}
 	}
-	
+
 	override addGetPortOperation(Class implementation, PortInfo portInfo, Interface providedIntf, String portName) {
 		// port provides an interface, add "get_p" operation and implementation
 		val opName = PrefixConstants.getP_Prefix + portName
@@ -139,7 +160,7 @@
 			var connectedDelegations = 0
 			for (ce : ces) {
 				val role = ce.role
-				
+
 				if (role instanceof Port) {
 					val rolePort = role as Port
 					if (rolePort.provideds.contains(providedIntf)) {
@@ -148,7 +169,8 @@
 				} else {
 					if (role instanceof Property) {
 						val roleType = (role as Property).type;
-						if (roleType instanceof BehavioredClassifier && (roleType as BehavioredClassifier).getInterfaceRealization(null, providedIntf) !== null) {
+						if (roleType instanceof BehavioredClassifier &&
+							(roleType as BehavioredClassifier).getInterfaceRealization(null, providedIntf) !== null) {
 							connectedDelegations++
 						}
 					}
@@ -159,342 +181,24 @@
 			var String body
 
 			if (isMultipleDelegations) {
-				// Check how many delegated parts there are
-				var providers = new BasicEList<Property>();
-				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 (part.upper > 1) {
-								for (var i = 0; i < part.upper; i++) {
-									providers.add(part)
-								}
-							} else {
-								providers.add(part)
-							}
-						}
-					} else {
-						if (role instanceof Property) {
-							val roleType = (role as Property).type;
-							if (roleType instanceof BehavioredClassifier && (roleType as BehavioredClassifier).getInterfaceRealization(null, providedIntf) !== null) {
-								if (part.upper > 1) {
-									for (var i = 0; i < part.upper; i++) {
-										providers.add(role)
-									}
-								} else {
-									providers.add(role)
-								}
-							}
-						}
-					}
-				}
-				
-				// We need to create a port representing the delegating port
-				val attributeName = PrefixConstants.attributePrefix + portName
-				
-				// We need to create a broadcast class
-				val broadcastClassName = '''«implementation.name»_«providedIntf.name»_«portName»'''
-
-				var attr = implementation.getOwnedAttribute(attributeName, null)
-				if (attr === null || attr instanceof Port) {
-					if (implementation.owner instanceof Package) {
-						// Create the broadcast class
-						val broadcastClass = (implementation.owner as Package).createOwnedClass(broadcastClassName, false)
-
-						// Set its interface realization
-						broadcastClass.createInterfaceRealization("delegate" + providedIntf, providedIntf)
-
-						// Create the references array
-						var references = broadcastClass.createOwnedAttribute("references", providedIntf)
-						StereotypeUtil.apply(references, Ptr)
-						references.lower = providers.size
-						references.upper = providers.size
-
-						// Create an refIndex attribute
-						var eLong = ElementUtils.getQualifiedElementFromRS(copier.source, PrefixConstants.INDEX_TYPE_FOR_MULTI_RECEPTACLE)
-						if (eLong !== null) {
-							eLong = copier.getCopy(eLong);
-						}
-						if (eLong instanceof Type) {
-							broadcastClass.createOwnedAttribute("refIndex", eLong)
-						} else {
-							throw new RuntimeException(
-								String.format(
-									"Can not find type %s. Thus, unable to create suitable connect operation in component to OO transformation",
-									PrefixConstants.INDEX_TYPE_FOR_MULTI_RECEPTACLE));
-						}
-
-						// Create the constructor
-						var constructor = broadcastClass.createOwnedOperation(broadcastClassName, null, null, null)
-						StereotypeUtil.apply(constructor, Create)
-						val constructorBehavior = broadcastClass.createOwnedBehavior(broadcastClassName, UMLPackage.eINSTANCE.getOpaqueBehavior()) as OpaqueBehavior
-						constructor.getMethods().add(constructorBehavior)
-						constructorBehavior.getLanguages().add(progLang)
-						constructorBehavior.getBodies.add("refIndex = 0;")
-						
-						// Create the connect method
-						val connectOpName = PrefixConstants.connectQ_Prefix + portName
-						val connectOperation = broadcastClass.createOwnedOperation(connectOpName, null, null)
-						val connectRefParam = connectOperation.createOwnedParameter("ref", providedIntf)
-						applyRef(connectRefParam)
-						val connectBehavior = broadcastClass.createOwnedBehavior(connectOpName, UMLPackage.eINSTANCE.getOpaqueBehavior()) as OpaqueBehavior
-						connectOperation.getMethods().add(connectBehavior)
-						connectBehavior.getLanguages().add(progLang)
-						connectBehavior.getBodies.add(
-							'''
-							if (refIndex < «providers.size») {
-								references[refIndex] = ref;
-								refIndex++;
-							}
-							'''
-						)
-
-						// Create operations of realized interface in broadcast class
-						for (operation : providedIntf.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
-							copyCppOperationAndParameterStereotypes(operation, copiedOperation)
-							
-							// Create body
-							var delegationOperationBody = ""
-
-							var delegateOperationCall = operation.name + "("
-							var j = 0;
-							for (parameterName : parameterNames) {
-								j++
-								delegateOperationCall += parameterName
-								if (j < parameterNames.size) {
-									delegateOperationCall += ","
-								}
-							}
-							delegateOperationCall += ")"
-							
-							delegationOperationBody +=
-							'''
-							for (int i = 0; i < refIndex; i++) {
-								«IF parameterNamesWithReturn.size > parameterNames.size»
-								if (i < refIndex - 1) {
-									references[i]->«delegateOperationCall»;
-								}
-								«ELSE»
-								references[i]->«delegateOperationCall»;
-								«ENDIF»
-							}
-							«IF parameterNamesWithReturn.size > parameterNames.size»
-							return references[refIndex - 1]->«delegateOperationCall»;
-							«ENDIF»
-							'''
-	
-							val delegationOperationBehavior = broadcastClass.createOwnedBehavior(connectOpName, UMLPackage.eINSTANCE.getOpaqueBehavior()) as OpaqueBehavior
-							delegationOperation.getMethods().add(delegationOperationBehavior)
-	
-							delegationOperationBehavior.getLanguages().add(progLang)
-							delegationOperationBehavior.getBodies().add(delegationOperationBody)
-							
-						}
-
-						// Create the attribute in implementation for the port and type it with the broadcast class
-						attr = implementation.createOwnedAttribute(attributeName, broadcastClass)
-						CopyUtils.copyMultElemModifiers(portInfo.port, attr)
-						attr.setAggregation(AggregationKind.SHARED_LITERAL)
-						
-						// Connect delegated parts (either properties or ports) to the broadcast class
-						var connectionCode = ""
-						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 (var i = 0; i < part.upper; i++) {
-												connectionCode += '''«attributeName»->«connectOpName»(«part.name»[«i»].«PrefixConstants.getP_Prefix»«role.name»«providedIntf.name»());''' + NL
-											}
-										} else {
-											connectionCode += '''«attributeName»->«connectOpName»(«part.nameRef»«PrefixConstants.getP_Prefix»«role.name»«providedIntf.name»());''' + NL
-										}
-									} else {
-										if (part.upper > 1) {
-											for (var i = 0; i < part.upper; i++) {
-												connectionCode += '''«attributeName»->«connectOpName»(«part.name»[«i»].«PrefixConstants.getP_Prefix»«role.name»());''' + NL
-											}
-										} else {
-											connectionCode += '''«attributeName»->«connectOpName»(«part.nameRef»«PrefixConstants.getP_Prefix»«role.name»());''' + NL
-										}
-									}
-								}
-							} 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 (var i = 0; i < (role as Property).upper; i++) {
-												connectionCode += '''«attributeName»->«connectOpName»(«role.name»[«i»]);''' + NL
-											}
-										} else {
-											connectionCode += '''«attributeName»->«connectOpName»(«role.name»);''' + NL
-										}
-									}
-								}
-							}
-						}
-
-						body = '''if (!«attributeName») {
-							«attributeName» = new «broadcastClassName»();
-						}
-						«connectionCode.trim»
-						return «attributeName»;
-						'''
-					}	
-				}
-
-				// Below is the old delegation method, where the delegation port's owner itself implements the broadcast, instead of using a broadcast class.
-//				// Return port owner (class)
-//				body = "return this;"
-//				// TODO
-//
-//				// Create interface realization in port owner (class)
-//				if (!implementation.interfaceRealizations.contains(providedIntf)) {
-//					implementation.createInterfaceRealization("delegate" + providedIntf.name, providedIntf);
-//				}
-//
-//				// Create operations of realized interface in port owner (class)
-//				for (operation : providedIntf.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)
-//					}
-//
-//					// Create an operation only if the port owner does not already have the operation (user-defined delegation)
-//					if (implementation.getOperation(operation.name, parameterNamesWithReturn, parameterTypesWithReturn) === null) {
-//						// Copy operation of interface in class
-//						val copiedOperation = EcoreUtil.copy(operation);
-//						//val copiedOperation = copier.getCopy(operation);
-//						implementation.ownedOperations.add(copiedOperation);
-//						var delegationOperation = copiedOperation;
-//						//var delegationOperation = implementation.createOwnedOperation(operation.name, parameterNames, parameterTypes, operation.type);
-//						
-//						// Copy stereotype applications
-//						copyCppOperationAndParameterStereotypes(operation, copiedOperation)
-//						
-//						// Create body
-//						var delegationOperationBody = ""
-//						var i = 0;
-//						for (ce : ces) {
-//							i++
-//							val part = ce.partWithPort
-//							val role = ce.role
-//	
-//							var delegateOperationCall = operation.name + "("
-//							var j = 0;
-//							for (parameterName : parameterNames) {
-//								j++
-//								delegateOperationCall += parameterName
-//								if (j < parameterNames.size) {
-//									delegateOperationCall += ","
-//								}
-//							}
-//							delegateOperationCall += ")"
-//
-//							if (role instanceof Port) {
-//								val rolePort = role as Port
-//								if (rolePort.provideds.contains(providedIntf)) {
-//									if (i >= ces.size && parameterNamesWithReturn.size > parameterNames.size) {
-//										// We return the result of the last call (no determinism is ensured)
-//										delegationOperationBody += "return "
-//									}
-//
-//									if (rolePort.provideds.size > 1) {
-//										delegationOperationBody += '''«part.nameRef»«PrefixConstants.getP_Prefix»«role.name»«providedIntf.name»()->«delegateOperationCall»;'''
-//									} else {
-//										delegationOperationBody += '''«part.nameRef»«PrefixConstants.getP_Prefix»«role.name»()->«delegateOperationCall»;'''
-//									}
-//	
-//									if (i < ces.size) {
-//										delegationOperationBody += NL
-//									}
-//								}
-//							} else {
-//								// role is not a port: connector connects directly to a
-//								// structural feature without passing via a port
-//								if (role instanceof Property) {
-//									val roleType = (role as Property).type;
-//									if (roleType instanceof BehavioredClassifier && (roleType as BehavioredClassifier).getInterfaceRealization(null, providedIntf) !== null) {
-//										if (i >= ces.size && parameterNamesWithReturn.size > parameterNames.size) {
-//											// We return the result of the last call (no determinism is ensured)
-//											delegationOperationBody += "return "
-//										}
-//
-//										delegationOperationBody += role.name + "->" + delegateOperationCall + ";"
-//
-//										if (i < ces.size) {
-//											delegationOperationBody += NL
-//										}
-//									}
-//								}
-//							}
-//						}
-//
-//						if (delegationOperationBody.empty) {
-//							throw new RuntimeException(
-//							String.format(
-//								"Interface <%s> provided by port <%s> of class <%s> is not implemented by the component itself nor does the port delegate to a part",
-//								providedIntf.name, portName, implementation.name))
-//						}
-//
-//						val delegationOperationBehavior = implementation.createOwnedBehavior(opName, UMLPackage.eINSTANCE.getOpaqueBehavior()) as OpaqueBehavior
-//						delegationOperation.getMethods().add(delegationOperationBehavior)
-//
-//						delegationOperationBehavior.getLanguages().add(progLang)
-//						delegationOperationBehavior.getBodies().add(delegationOperationBody)
-//					}
-//				}
+				val dc = new CreateMultiRefClass(this, copier)
+				body = dc.createDelegationProvided(implementation, ces, portInfo.port, portName, providedIntf);
 			} else if (!ces.empty) {
 				// If there is an delegation to one, and one only, inner property, delegate to it
 				// Make distinction between delegation to a port of the class typing an inner property or the property itself
 				body = "return "
-				
+
 				var i = 0
 				while (i < ces.size && body.equals("return ")) {
 					val part = ces.get(i).partWithPort
 					val role = ces.get(i).role
-					
+
 					if (role instanceof Port) {
 						val rolePort = role as Port
 						if (rolePort.provideds.contains(providedIntf)) {
 							if (rolePort.provideds.size > 1 || !(rolePort.type instanceof Interface)) {
-								body += '''«part.nameRef»«PrefixConstants.getP_Prefix»«role.name»«providedIntf.name»();'''
+								body +=
+									'''«part.nameRef»«PrefixConstants.getP_Prefix»«role.name»«providedIntf.name»();'''
 							} else {
 								body += '''«part.nameRef»«PrefixConstants.getP_Prefix»«role.name»();'''
 							}
@@ -504,14 +208,16 @@
 						// structural feature without passing via a port
 						if (role instanceof Property) {
 							val roleType = (role as Property).type;
-							if (roleType instanceof BehavioredClassifier && (roleType as BehavioredClassifier).getInterfaceRealization(null, providedIntf) !== null) {
+							if (roleType instanceof BehavioredClassifier &&
+								(roleType as BehavioredClassifier).getInterfaceRealization(null, providedIntf) !==
+									null) {
 								body += role.name
 							}
 						}
 					}
 					i++
 				}
-				
+
 				if (body.equals("return ")) {
 					body += "NULL;"
 				}
@@ -542,7 +248,7 @@
 			behavior.getBodies().add(body)
 		}
 	}
-	
+
 	override addConnectPortOperation(Class implementation, PortInfo portInfo, Interface requiredIntf, String portName) {
 		// port requires an interface, add "connect_p" operation and implementation
 		val opName = PrefixConstants.connectQ_Prefix + portName
@@ -553,24 +259,6 @@
 			// ports, we may have to do that.
 		} else {
 			var op = implementation.createOwnedOperation(opName, null, null)
-			val boolean multiPort = (portInfo.getUpper() > 1) || (portInfo.getUpper() == -1) // -1 indicates "*"
-			if (multiPort) {
-
-				// add index parameter
-				var eLong = ElementUtils.getQualifiedElementFromRS(copier.source,
-					PrefixConstants.INDEX_TYPE_FOR_MULTI_RECEPTACLE)
-				if (eLong !== null) {
-					eLong = copier.getCopy(eLong);
-				}
-				if (eLong instanceof Type) {
-					op.createOwnedParameter("index", eLong)
-				} else {
-					throw new RuntimeException(
-						String.format(
-							"Can not find type %s. Thus, unable to create suitable connect operation in component to OO transformation",
-							PrefixConstants.INDEX_TYPE_FOR_MULTI_RECEPTACLE));
-				}
-			}
 			val refParam = op.createOwnedParameter("ref", requiredIntf)
 			applyRef(refParam)
 
@@ -602,21 +290,15 @@
 
 							if (part.upper > 1) {
 								for (var j = 0; j < part.upper; j++) {
-									bodyConstruction += '''«part.name»[«i»].«targetOpName»'''
+									bodyConstruction += '''«part.name»[«i»].«targetOpName»(ref);'''
 								}
 							} else {
-								bodyConstruction += '''«part.nameRef»«targetOpName»'''
-							}
-
-							// TODO: no check that multiplicity of both port matches
-							if ((portInfo.getUpper() > 1) || (portInfo.getUpper() == -1)) {
-								bodyConstruction += "(index, ref);"
-							} else {
-								bodyConstruction += "(ref);"
+								bodyConstruction += '''«part.nameRef»«targetOpName»(ref);'''
 							}
 						}
 					} else {
-						if (part.type instanceof Classifier && (part.type as Classifier).getAllUsedInterfaces().contains(requiredIntf)) {
+						if (part.type instanceof Classifier &&
+							(part.type as Classifier).getAllUsedInterfaces().contains(requiredIntf)) {
 							if (part.upper > 1) {
 								for (var j = 0; j < part.upper; j++) {
 									bodyConstruction += '''«part.name»[«i»];'''
@@ -637,158 +319,24 @@
 					i++
 				}
 			} else {
-				var providers = new BasicEList<Property>();
-				var visitedConnectors = new UniqueEList<Connector>();
-				getAllConnectedProviders(portInfo.port, requiredIntf, providers, visitedConnectors)
-				
+
 				val attributeName = PrefixConstants.attributePrefix + portName
-				
-				if (providers.size > 1) {
-					// TODO refactor broadcast class creation code with similar code in addGetPortOperation()
+				val port = portInfo.port
 
-					// We need to create a broadcast class
-					val broadcastClassName = '''«implementation.name»_«requiredIntf.name»_«portName»'''
-
-					var attr = implementation.getOwnedAttribute(attributeName, null)
-					if (attr === null || attr instanceof Port) {
-						if (implementation.owner instanceof Package) {
-							// Create the broadcast class
-							val broadcastClass = (implementation.owner as Package).createOwnedClass(broadcastClassName, false)
-
-							// Set its interface realization
-							broadcastClass.createInterfaceRealization("broadcast" + requiredIntf, requiredIntf)
-
-							// Create the references array
-							var references = broadcastClass.createOwnedAttribute("references", requiredIntf)
-							StereotypeUtil.apply(references, Ptr)
-							references.lower = providers.size
-							references.upper = providers.size
-
-							// Create an refIndex attribute
-							var eLong = ElementUtils.getQualifiedElementFromRS(copier.source, PrefixConstants.INDEX_TYPE_FOR_MULTI_RECEPTACLE)
-							if (eLong !== null) {
-								eLong = copier.getCopy(eLong);
-							}
-							if (eLong instanceof Type) {
-								broadcastClass.createOwnedAttribute("refIndex", eLong)
-							} else {
-								throw new RuntimeException(
-									String.format(
-										"Can not find type %s. Thus, unable to create suitable connect operation in component to OO transformation",
-										PrefixConstants.INDEX_TYPE_FOR_MULTI_RECEPTACLE));
-							}
-
-							// Create the constructor
-							var constructor = broadcastClass.createOwnedOperation(broadcastClassName, null, null, null)
-							StereotypeUtil.apply(constructor, Create)
-							val constructorBehavior = broadcastClass.createOwnedBehavior(broadcastClassName, UMLPackage.eINSTANCE.getOpaqueBehavior()) as OpaqueBehavior
-							constructor.getMethods().add(constructorBehavior)
-							constructorBehavior.getLanguages().add(progLang)
-							constructorBehavior.getBodies.add("refIndex = 0;")
-							
-							// Create the connect method
-							val connectOperation = broadcastClass.createOwnedOperation(opName, null, null)
-							val connectRefParam = connectOperation.createOwnedParameter("ref", requiredIntf)
-							applyRef(connectRefParam)
-							val connectBehavior = broadcastClass.createOwnedBehavior(opName, UMLPackage.eINSTANCE.getOpaqueBehavior()) as OpaqueBehavior
-							connectOperation.getMethods().add(connectBehavior)
-							connectBehavior.getLanguages().add(progLang)
-							connectBehavior.getBodies.add(
-								'''
-								if (refIndex < «providers.size») {
-									references[refIndex] = ref;
-									refIndex++;
-								}
-								'''
-							)
-
-							// Create operations of realized interface in broadcast class
-							for (operation : requiredIntf.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
-								copyCppOperationAndParameterStereotypes(operation, copiedOperation)
-								
-								// Create body
-								var delegationOperationBody = ""
-
-								var delegateOperationCall = operation.name + "("
-								var j = 0;
-								for (parameterName : parameterNames) {
-									j++
-									delegateOperationCall += parameterName
-									if (j < parameterNames.size) {
-										delegateOperationCall += ","
-									}
-								}
-								delegateOperationCall += ")"
-								
-								delegationOperationBody +=
-								'''
-								for (int i = 0; i < refIndex; i++) {
-									«IF parameterNamesWithReturn.size > parameterNames.size»
-									if (i < refIndex - 1) {
-										references[i]->«delegateOperationCall»;
-									}
-									«ELSE»
-									references[i]->«delegateOperationCall»;
-									«ENDIF»
-								}
-								«IF parameterNamesWithReturn.size > parameterNames.size»
-								return references[refIndex - 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)
-								
-							}
-
-							// Create the attribute in implementation for the port and type it with the broadcast class
-							attr = implementation.createOwnedAttribute(attributeName, broadcastClass)
-							CopyUtils.copyMultElemModifiers(portInfo.port, attr)
-							attr.setAggregation(AggregationKind.SHARED_LITERAL)
-							
-							body = '''if (!«attributeName») {
-								«attributeName» = new «broadcastClassName»();
-							}
-							«attributeName»->«opName»(«IF multiPort»index, «ENDIF»ref);
-							'''
-						}
-					}
+				if (port.upper != 1) {
+					val dc = new CreateMultiRefClass(this, copier)
+					body += dc.createDelegationRequired(implementation, portName, requiredIntf);
 				} else {
 					// No delegation and no multiple providers
 					var attr = implementation.getOwnedAttribute(attributeName, null)
 					if (attr === null || attr instanceof Port) {
 						attr = implementation.createOwnedAttribute(attributeName, requiredIntf)
 						CopyUtils.copyMultElemModifiers(portInfo.port, attr)
-	
+
 						// is shared (should store a reference)
 						attr.setAggregation(AggregationKind.SHARED_LITERAL)
 					}
-					body = attributeName
-					if(multiPort) body += "[index]"
-					body += " = ref;"
+					body += '''«attributeName» = ref;'''
 				}
 			}
 
@@ -802,7 +350,6 @@
 			// TODO: reconsider optimization that delegated required ports do not have a
 			// local attribute and associated operation (an inner class may delegate, but the
 			// composite may be using it as well).
-			
 			if ((PrefixConstants.getConnQ_Prefix.length() > 0) && (!ces.empty)) {
 				val getConnOpName = PrefixConstants.getConnQ_Prefix + portName
 				var getConnOp = implementation.getOwnedOperation(getConnOpName, null, null)
@@ -821,13 +368,12 @@
 				body = '''return «name»;'''
 				behavior.getLanguages().add(progLang)
 				behavior.getBodies().add(body.trim)
-			}
-			else {
+			} else {
 			}
 		}
 	}
-	
-	override connectPorts(Map<MultiplicityElement, Integer> indexMap, Connector connector, ConnectorEnd receptacleEnd,
+
+	override connectPorts(Connector connector, ConnectorEnd receptacleEnd,
 		ConnectorEnd facetEnd, Port subPort) throws TransformationException {
 		val association = connector.type
 		if ((receptacleEnd.role instanceof Port) && (facetEnd.role instanceof Port)) {
@@ -842,58 +388,58 @@
 
 				var subPortName = ""
 				if(subPort !== null) subPortName += "_" + subPort.name
-				val indexName = getIndexName(indexMap, receptaclePort, receptacleEnd)
-				
+
 				var result = ""
-				
+
 				if (receptaclePI.getRequireds().size == 1 && receptaclePI.port.type instanceof Interface) { // receptaclePort requires only 1 interface
 					var facetPortName = ""
 
 					if (facetPI.getProvideds().size == 1 && facetPI.port.type instanceof Interface) { // Original behavior in case of single interface, where we always connect without check of interface consistency
 						facetPortName = facetPI.name
-					} else if (facetPI.getProvideds().size >= 1 && facetPI.getProvideds().contains(receptaclePI.getRequired())) {
+					} else if (facetPI.getProvideds().size >= 1 &&
+						facetPI.getProvideds().contains(receptaclePI.getRequired())) {
 						facetPortName += facetPI.name + receptaclePI.getRequired().name
-					} 
+					}
 
 					if (!facetPortName.empty) {
 						val setter = '''«receptaclePart.nameRef»connect_«receptaclePort.name»«subPortName»'''
 						if (facetPart.upper > 1) {
 							for (var i = 0; i < facetPart.upper; i++) {
 								val getter = '''«facetPart.name»[«i»].get_«facetPortName»«subPortName»()'''
-								result += '''«setter»(«indexName»«getter»);''' + NL
+								result += '''«setter»(«getter»);''' + NL
 							}
 						} else {
 							val getter = '''«facetPart.nameRef»get_«facetPortName»«subPortName»()'''
-							result += '''«setter»(«indexName»«getter»);''' + NL
+							result += '''«setter»(«getter»);''' + NL
 						}
 					}
 				} else { // receptaclePort requires several interfaces or one interface through a class
 					for (requiredInterface : receptaclePI.getRequireds()) {
 						var receptaclePortName = receptaclePI.name + requiredInterface.name
 						var facetPortName = ""
-						
+
 						if (facetPI.getProvideds().contains(requiredInterface)) {
 							facetPortName += facetPI.name
 							if (facetPI.getProvideds().size > 1 || !(facetPI.port.type instanceof Interface)) {
 								facetPortName += requiredInterface.name
-							} 
+							}
 						}
-						
+
 						if (!facetPortName.empty) {
 							val setter = '''«receptaclePart.nameRef»connect_«receptaclePortName»«subPortName»'''
 							if (facetPart.upper > 1) {
 								for (var i = 0; i < facetPart.upper; i++) {
 									val getter = '''«facetPart.name»[«i»].get_«facetPortName»«subPortName»()'''
-									result += '''«setter»(«indexName»«getter»);''' + NL
+									result += '''«setter»(«getter»);''' + NL
 								}
 							} else {
 								val getter = '''«facetPart.nameRef»get_«facetPortName»«subPortName»()'''
-								result += '''«setter»(«indexName»«getter»);''' + NL
+								result += '''«setter»(«getter»);''' + NL
 							}
 						}
 					}
 				}
-				
+
 				return result
 			}
 		} else if (receptacleEnd.role instanceof Port) {
@@ -904,22 +450,21 @@
 				val facetPart = facetEnd.role as Property
 				val receptaclePart = facetEnd.partWithPort
 
-				val indexName = getIndexName(indexMap, receptaclePort, receptacleEnd)
 				var result = ""
-				
+
 				if (receptaclePort.getRequireds().size > 1) { // receptaclePort requires several interfaces
 					for (requiredInterface : receptaclePort.getRequireds()) {
 						var receptaclePortName = receptaclePort.name + requiredInterface.name
-						
+
 						val setter = '''«receptaclePart.nameRef»connect_«receptaclePortName»'''
 						if (facetPart.upper > 1) {
 							for (var i = 0; i < facetPart.upper; i++) {
 								val getter = '''«facetPart.name»[«i»]'''
-								result += '''«setter»(«indexName»«getter»);''' + NL
+								result += '''«setter»(«getter»);''' + NL
 							}
 						} else {
 							val getter = '''«facetPart.getRef»'''
-							result += '''«setter»(«indexName»«getter»);''' + NL
+							result += '''«setter»(«getter»);''' + NL
 						}
 					}
 				} else {
@@ -927,11 +472,11 @@
 					if (facetPart.upper > 1) {
 						for (var i = 0; i < facetPart.upper; i++) {
 							val getter = '''«facetPart.name»[«i»]'''
-							result += '''«setter»(«indexName»«getter»);''' + NL
+							result += '''«setter»(«getter»);''' + NL
 						}
 					} else {
 						val getter = '''«facetPart.getRef»'''
-						result += '''«setter»(«indexName»«getter»);''' + NL
+						result += '''«setter»(«getter»);''' + NL
 					}
 				}
 
@@ -944,9 +489,9 @@
 			if (PortUtils.getProvided(facetPort) !== null) {
 				val facetPart = facetEnd.partWithPort
 				val receptaclePart = facetEnd.role as Property
-				
+
 				var result = ""
-				
+
 				if (facetPort.getProvideds().size > 1) { // facetPort provides several interfaces
 					for (providedInterface : facetPort.getProvideds()) {
 						var facetPortName = facetPort.name + providedInterface.name
@@ -973,7 +518,7 @@
 						result += '''«setter» = «getter»;''' + NL
 					}
 				}
-				
+
 				return result
 			}
 		} else if (association !== null) {
@@ -990,16 +535,6 @@
 			if ((assocProp1 !== null) && assocProp1.isNavigable) {
 				var setter = '''«receptaclePart.name».«assocProp1.name»'''
 				val getter = '''«facetPart.name»'''
-				if (assocProp1.upper != 1) {
-					// handle association ends with multiplicty != 1, use same map as for ports
-					var indexValue = indexMap.get(assocProp1)
-					if (indexValue === null) {
-						indexValue = new Integer(0)
-						indexMap.put(assocProp1, indexValue)
-					}
-					setter += '''[«indexValue++»]'''
-					indexMap.put(assocProp1, indexValue)
-				}
 				return '''«setter» = «getter»;''' + NL
 			}
 
@@ -1079,12 +614,13 @@
 			if (UMLUtil.getStereotypeApplication(source, Variadic) !== null) {
 				StereotypeUtil.apply(target, Variadic)
 			}
-			
+
 			if (source instanceof Operation && target instanceof Operation) {
 				if ((source as Operation).ownedParameters.size == (target as Operation).ownedParameters.size) {
 					var i = 0
 					while (i < (source as Operation).ownedParameters.size) {
-						copyCppOperationAndParameterStereotypes((source as Operation).ownedParameters.get(i), (target as Operation).ownedParameters.get(i))
+						copyCppOperationAndParameterStereotypes((source as Operation).ownedParameters.get(i),
+							(target as Operation).ownedParameters.get(i))
 						i++
 					}
 				}
diff --git a/plugins/components/org.eclipse.papyrus.designer.components.transformation/src/org/eclipse/papyrus/designer/components/transformation/component/PrefixConstants.java b/plugins/components/org.eclipse.papyrus.designer.components.transformation/src/org/eclipse/papyrus/designer/components/transformation/component/PrefixConstants.java
index d0ec17d..85da7ae 100644
--- a/plugins/components/org.eclipse.papyrus.designer.components.transformation/src/org/eclipse/papyrus/designer/components/transformation/component/PrefixConstants.java
+++ b/plugins/components/org.eclipse.papyrus.designer.components.transformation/src/org/eclipse/papyrus/designer/components/transformation/component/PrefixConstants.java
@@ -37,7 +37,7 @@
 		UML, CCM
 	}
 
-	public static final String INDEX_TYPE_FOR_MULTI_RECEPTACLE = "PrimitiveTypes::Integer"; //$NON-NLS-1$;
+	public static final String TYPE_FOR_MULTI_RECEPTACLE = "std::vector"; //$NON-NLS-1$;
 
 	/**
 	 * Initialize a specific CIF variant