Merge branch 'master' into bugs/401682

Conflicts:
	tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/UMLBugTests.java
diff --git a/plugins/org.eclipse.uml2.uml.resources/src/org/eclipse/uml2/uml/resources/util/UMLResourcesUtil.java b/plugins/org.eclipse.uml2.uml.resources/src/org/eclipse/uml2/uml/resources/util/UMLResourcesUtil.java
index 3d28f82..2b66d3f 100644
--- a/plugins/org.eclipse.uml2.uml.resources/src/org/eclipse/uml2/uml/resources/util/UMLResourcesUtil.java
+++ b/plugins/org.eclipse.uml2.uml.resources/src/org/eclipse/uml2/uml/resources/util/UMLResourcesUtil.java
@@ -138,7 +138,8 @@
 	 */
 	public static void initGlobalRegistries() {
 		initPackageRegistry(EPackage.Registry.INSTANCE);
-		initEPackageNsURIToProfileLocationMap(UMLPlugin.getEPackageNsURIToProfileLocationMap());
+		initEPackageNsURIToProfileLocationMap(UMLPlugin
+			.getEPackageNsURIToProfileLocationMap());
 		initURIConverterURIMap(URIConverter.URI_MAP);
 		initContentHandlerRegistry(ContentHandler.Registry.INSTANCE);
 		initResourceFactoryRegistry(Resource.Factory.Registry.INSTANCE);
@@ -215,21 +216,21 @@
 	public static EPackage.Registry initPackageRegistry(
 			EPackage.Registry packageRegistry) {
 		packageRegistry.put(EcorePackage.eNS_URI, EcorePackage.eINSTANCE);
-	
+
 		packageRegistry.put(TypesPackage.eNS_URI, TypesPackage.eINSTANCE);
-	
+
 		packageRegistry.put(UML2_UML_PACKAGE_2_0_NS_URI, UMLPackage.eINSTANCE);
-	
+
 		packageRegistry.put(UML212UMLResource.UML_METAMODEL_NS_URI,
 			UMLPackage.eINSTANCE);
 		packageRegistry.put(UML302UMLResource.UML_METAMODEL_NS_URI,
 			UMLPackage.eINSTANCE);
-	
+
 		packageRegistry.put(UMLPackage.eNS_URI, UMLPackage.eINSTANCE);
-	
+
 		packageRegistry.put(UML302UMLResource.STANDARD_PROFILE_NS_URI,
 			L2Package.eINSTANCE);
-	
+
 		packageRegistry.put(L2Package.eNS_URI, L2Package.eINSTANCE);
 		packageRegistry.put(L3Package.eNS_URI, L3Package.eINSTANCE);
 
@@ -250,11 +251,15 @@
 	 */
 	public static Resource.Factory.Registry initResourceFactoryRegistry(
 			Resource.Factory.Registry resourceFactoryRegistry) {
-		Map<String, Object> extensionToFactoryMap = resourceFactoryRegistry.getExtensionToFactoryMap();
-		extensionToFactoryMap.put(UMLResource.FILE_EXTENSION, UMLResource.Factory.INSTANCE);
-		
-		Map<String, Object> contentTypeToFactoryMap = resourceFactoryRegistry.getContentTypeToFactoryMap();
-		contentTypeToFactoryMap.put(UMLResource.UML_CONTENT_TYPE_IDENTIFIER, UMLResource.Factory.INSTANCE);
+		Map<String, Object> extensionToFactoryMap = resourceFactoryRegistry
+			.getExtensionToFactoryMap();
+		extensionToFactoryMap.put(UMLResource.FILE_EXTENSION,
+			UMLResource.Factory.INSTANCE);
+
+		Map<String, Object> contentTypeToFactoryMap = resourceFactoryRegistry
+			.getContentTypeToFactoryMap();
+		contentTypeToFactoryMap.put(UMLResource.UML_CONTENT_TYPE_IDENTIFIER,
+			UMLResource.Factory.INSTANCE);
 
 		return resourceFactoryRegistry;
 	}
@@ -279,16 +284,15 @@
 		if (contentHandlers == null
 			|| !contentHandlers.contains(XMI_CONTENT_HANDLER)) {
 
-			contentHandlerRegistry.put(
-				ContentHandler.Registry.LOW_PRIORITY, XMI_CONTENT_HANDLER);
+			contentHandlerRegistry.put(ContentHandler.Registry.LOW_PRIORITY,
+				XMI_CONTENT_HANDLER);
 		}
 
 		contentHandlers = contentHandlerRegistry
 			.get(ContentHandler.Registry.NORMAL_PRIORITY);
 
 		if (contentHandlers == null) {
-			contentHandlerRegistry.put(
-				ContentHandler.Registry.NORMAL_PRIORITY,
+			contentHandlerRegistry.put(ContentHandler.Registry.NORMAL_PRIORITY,
 				contentHandlers = new ArrayList<ContentHandler>());
 		}
 
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Artifact.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Artifact.java
index 621e2b6..68dd50e 100644
--- a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Artifact.java
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Artifact.java
@@ -8,7 +8,7 @@
  * Contributors:
  *   IBM - initial API and implementation
  *   Kenn Hussey (CEA) - 327039, 351774
- *   Christian W. Damus (CEA) - 251963
+ *   Christian W. Damus (CEA) - 251963, 269598
  *
  */
 package org.eclipse.uml2.uml;
@@ -20,6 +20,7 @@
 /**
  * <!-- begin-user-doc -->
  * A representation of the model object '<em><b>Artifact</b></em>'.
+ * @extends AttributeOwner, OperationOwner
  * <!-- end-user-doc -->
  *
  * <!-- begin-model-doc -->
@@ -44,7 +45,7 @@
  * @generated
  */
 public interface Artifact
-		extends Classifier, DeployedArtifact {
+		extends Classifier, DeployedArtifact, AttributeOwner, OperationOwner {
 
 	/**
 	 * Returns the value of the '<em><b>File Name</b></em>' attribute.
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/AttributeOwner.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/AttributeOwner.java
new file mode 100644
index 0000000..a664f80
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/AttributeOwner.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2013 CEA 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
+ *
+ * Contributors:
+ *   Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.uml2.uml;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EClass;
+
+/**
+ * Common protocol for {@linkplain Classifier classifiers} that own
+ * {@linkplain Classifier#getAttributes() attributes}.
+ * 
+ * @since 4.2
+ */
+public interface AttributeOwner {
+
+	/**
+	 * Obtains the attributes owned by this classifier.
+	 * 
+	 * @return my owned attributes
+	 */
+	EList<Property> getOwnedAttributes();
+
+	/**
+	 * Creates a new {@link Property} as an owned attribute of this classifier.
+	 * 
+	 * @param name
+	 *            the name of the new attribute (may be {@code null})
+	 * @param type
+	 *            the type of the new attribute (may be {@code null})
+	 * 
+	 * @return the new owned attribute
+	 * 
+	 * @see #createOwnedAttribute(String, Type, EClass)
+	 * @see #getOwnedAttribute(String, Type)
+	 */
+	Property createOwnedAttribute(String name, Type type);
+
+	/**
+	 * Creates a new property as an owned attribute of this classifier.
+	 * 
+	 * @param name
+	 *            the name of the new attribute (may be {@code null})
+	 * @param type
+	 *            the type of the new attribute (may be {@code null})
+	 * @param eClass
+	 *            the Ecore metaclass of the attribute to create
+	 * 
+	 * @return the new owned attribute
+	 * 
+	 * @see #createOwnedAttribute(String, Type)
+	 * @see #getOwnedAttribute(String, Type, boolean, EClass, boolean)
+	 */
+	Property createOwnedAttribute(String name, Type type, EClass eClass);
+
+	/**
+	 * Finds the first owned attribute that matches the given {@code name}
+	 * and/or {@code type}.
+	 * 
+	 * @param name
+	 *            the attribute name to match, or {@null} to match any
+	 *            attribute name
+	 * @param type
+	 *            the attribute type to match, or {@null} to match any
+	 *            attribute type
+	 * 
+	 * @return any matching attribute, or {@code null} if not found
+	 * 
+	 * @see #getOwnedAttribute(String, Type, boolean, EClass, boolean)
+	 */
+	Property getOwnedAttribute(String name, Type type);
+
+	/**
+	 * Finds the first owned attribute that matches the given {@code name}
+	 * (optionally irrespective of case) and/or {@code type}.
+	 * 
+	 * @param name
+	 *            the attribute name to match, or {@null} to match any
+	 *            attribute name
+	 * @param type
+	 *            the attribute type to match, or {@null} to match any
+	 *            attribute type
+	 * @param ignoreCase
+	 *            whether to match names case-insensitively
+	 * @param eClass
+	 *            the Ecore metaclass of attribute to match, or {@code null} to
+	 *            match any kind of attribute
+	 * @param createOnDemand
+	 *            whether to create the owned attribute and return it if an
+	 *            existing match is not found
+	 * 
+	 * @return any matching attribute, or {@code null} if not found and
+	 *         {@code createOnDemand} is {@code false}
+	 * 
+	 * @see #getOwnedAttribute(String, Type)
+	 */
+	Property getOwnedAttribute(String name, Type type, boolean ignoreCase,
+			EClass eClass, boolean createOnDemand);
+
+}
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Class.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Class.java
index e934b45..a2506d0 100644
--- a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Class.java
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Class.java
@@ -9,7 +9,7 @@
  *   IBM - initial API and implementation
  *   Kenn Hussey (Embarcadero Technologies) - 205188
  *   Kenn Hussey (CEA) - 327039, 351774
- *   Christian W. Damus (CEA) - 251963
+ *   Christian W. Damus (CEA) - 251963, 269598
  *
  */
 package org.eclipse.uml2.uml;
@@ -25,6 +25,7 @@
 /**
  * <!-- begin-user-doc -->
  * A representation of the model object '<em><b>Class</b></em>'.
+ * @extends OperationOwner
  * <!-- end-user-doc -->
  *
  * <!-- begin-model-doc -->
@@ -52,7 +53,7 @@
  * @generated
  */
 public interface Class
-		extends EncapsulatedClassifier, BehavioredClassifier {
+		extends EncapsulatedClassifier, BehavioredClassifier, OperationOwner {
 
 	/**
 	 * Returns the value of the '<em><b>Owned Operation</b></em>' containment reference list.
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/DataType.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/DataType.java
index d781893..b428af5 100644
--- a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/DataType.java
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/DataType.java
@@ -8,7 +8,7 @@
  * Contributors:
  *   IBM - initial API and implementation
  *   Kenn Hussey (CEA) - 327039, 351774
- *   Christian W. Damus (CEA) - 251963
+ *   Christian W. Damus (CEA) - 251963, 269598
  *
  */
 package org.eclipse.uml2.uml;
@@ -20,6 +20,7 @@
 /**
  * <!-- begin-user-doc -->
  * A representation of the model object '<em><b>Data Type</b></em>'.
+ * @extends AttributeOwner, OperationOwner
  * <!-- end-user-doc -->
  *
  * <!-- begin-model-doc -->
@@ -40,7 +41,7 @@
  * @generated
  */
 public interface DataType
-		extends Classifier {
+		extends Classifier, AttributeOwner, OperationOwner {
 
 	/**
 	 * Returns the value of the '<em><b>Owned Attribute</b></em>' containment reference list.
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Interface.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Interface.java
index 8bcb99f..e930888 100644
--- a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Interface.java
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Interface.java
@@ -8,7 +8,7 @@
  * Contributors:
  *   IBM - initial API and implementation
  *   Kenn Hussey (CEA) - 327039, 351774
- *   Christian W. Damus (CEA) - 251963
+ *   Christian W. Damus (CEA) - 251963, 269598
  *
  */
 package org.eclipse.uml2.uml;
@@ -24,6 +24,7 @@
 /**
  * <!-- begin-user-doc -->
  * A representation of the model object '<em><b>Interface</b></em>'.
+ * @extends AttributeOwner, OperationOwner
  * <!-- end-user-doc -->
  *
  * <!-- begin-model-doc -->
@@ -50,7 +51,7 @@
  * @generated
  */
 public interface Interface
-		extends Classifier {
+		extends Classifier, AttributeOwner, OperationOwner {
 
 	/**
 	 * Returns the value of the '<em><b>Owned Attribute</b></em>' containment reference list.
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/OperationOwner.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/OperationOwner.java
new file mode 100644
index 0000000..f25a85f
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/OperationOwner.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2013 CEA 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
+ *
+ * Contributors:
+ *   Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.uml2.uml;
+
+import org.eclipse.emf.common.util.EList;
+
+/**
+ * Common protocol for {@linkplain Classifier classifiers} that own
+ * {@linkplain Classifier#getOperations() operations}.
+ * 
+ * @since 4.2
+ */
+public interface OperationOwner {
+
+	/**
+	 * Obtains the operations owned by this classifier.
+	 * 
+	 * @return my owned operations
+	 */
+	EList<Operation> getOwnedOperations();
+
+	/**
+	 * Creates a new void {@link Operation} (having no return result) as an
+	 * owned operation of this classifier.
+	 * 
+	 * @param name
+	 *            the name of the new operation (may be {@code null})
+	 * @param parameterNames
+	 *            the names of the operation's {@link ParameterDirectionKind#IN
+	 *            IN} parameters (may be {@code null} if no parameters are
+	 *            needed)
+	 * @param parameterTypes
+	 *            the types of the operation's {@link ParameterDirectionKind#IN
+	 *            IN} parameters (may be {@code null} if no parameters are
+	 *            needed)
+	 * 
+	 * @return the new owned operation
+	 * 
+	 * @see #createOwnedOperation(String, EList, EList, Type)
+	 * @see #getOwnedOperation(String, EList, EList)
+	 */
+	Operation createOwnedOperation(String name, EList<String> parameterNames,
+			EList<Type> parameterTypes);
+
+	/**
+	 * Creates a new {@link Operation} as an owned operation of this classifier.
+	 * 
+	 * @param name
+	 *            the name of the new operation (may be {@code null})
+	 * @param parameterNames
+	 *            the names of the operation's {@link ParameterDirectionKind#IN
+	 *            IN} parameters (may be {@code null} if no parameters are
+	 *            needed)
+	 * @param parameterTypes
+	 *            the types of the operation's {@link ParameterDirectionKind#IN
+	 *            IN} parameters (may be {@code null} if no parameters are
+	 *            needed)
+	 * @param returnType
+	 *            the type of the operation (which is the type of its sole
+	 *            {@linkplain ParameterDirectionKind#RETURN return result})
+	 * 
+	 * @return the new owned operation
+	 * 
+	 * @see #createOwnedOperation(String, EList, EList)
+	 * @see #getOwnedOperation(String, EList, EList)
+	 */
+	Operation createOwnedOperation(String name, EList<String> parameterNames,
+			EList<Type> parameterTypes, Type returnType);
+
+	/**
+	 * Finds the first owned operation that matches all or any of the given
+	 * {@code name}, {@code parameterNames}, and {@code parameterTypes}.
+	 * 
+	 * @param name
+	 *            the operation name to match, or {@null} to match any
+	 *            operation name
+	 * @param parameterNames
+	 *            the parameter names to match, or {@null} to match any
+	 *            parameter names
+	 * @param parameterTypes
+	 *            the parameter types to match, or {@null} to match any
+	 *            signature
+	 * 
+	 * @return any matching operation, or {@code null} if not found
+	 * 
+	 * @see #getOwnedOperation(String, EList, EList, boolean, boolean)
+	 */
+	Operation getOwnedOperation(String name, EList<String> parameterNames,
+			EList<Type> parameterTypes);
+
+	/**
+	 * Finds the first owned operation that matches all or any of the given
+	 * {@code name} (optionally case-insensitive), {@code parameterNames}
+	 * (optionally case-insensitive), and {@code parameterTypes}.
+	 * 
+	 * @param name
+	 *            the operation name to match, or {@null} to match any
+	 *            operation name
+	 * @param parameterNames
+	 *            the parameter names to match, or {@null} to match any
+	 *            parameter names
+	 * @param parameterTypes
+	 *            the parameter types to match, or {@null} to match any
+	 *            signature
+	 * @param ignoreCase
+	 *            whether matching of operation and parameter names is
+	 *            case-insensitive
+	 * @param createOnDemand
+	 *            whether to create the owned operation and return it if an
+	 *            existing match is not found
+	 * 
+	 * @return any matching operation, or {@code null} if not found and
+	 *         {@code createOnDemand} is {@code false}
+	 * 
+	 * @see #getOwnedOperation(String, EList, EList)
+	 */
+	Operation getOwnedOperation(String name, EList<String> parameterNames,
+			EList<Type> parameterTypes, boolean ignoreCase,
+			boolean createOnDemand);
+
+}
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Signal.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Signal.java
index 035f1dd..89049ff 100644
--- a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Signal.java
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/Signal.java
@@ -8,7 +8,7 @@
  * Contributors:
  *   IBM - initial API and implementation
  *   Kenn Hussey (CEA) - 327039, 351774
- *   Christian W. Damus (CEA) - 251963
+ *   Christian W. Damus (CEA) - 251963, 269598
  *
  */
 package org.eclipse.uml2.uml;
@@ -20,6 +20,7 @@
 /**
  * <!-- begin-user-doc -->
  * A representation of the model object '<em><b>Signal</b></em>'.
+ * @extends AttributeOwner
  * <!-- end-user-doc -->
  *
  * <!-- begin-model-doc -->
@@ -39,7 +40,7 @@
  * @generated
  */
 public interface Signal
-		extends Classifier {
+		extends Classifier, AttributeOwner {
 
 	/**
 	 * Returns the value of the '<em><b>Owned Attribute</b></em>' containment reference list.
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/StructuredClassifier.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/StructuredClassifier.java
index 7bb9d50..ee18397 100644
--- a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/StructuredClassifier.java
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/StructuredClassifier.java
@@ -9,7 +9,7 @@
  *   IBM - initial API and implementation
  *   Kenn Hussey (Embarcadero Technologies) - 205188
  *   Kenn Hussey (CEA) - 327039, 351774
- *   Christian W. Damus (CEA) - 251963
+ *   Christian W. Damus (CEA) - 251963, 269598
  *
  */
 package org.eclipse.uml2.uml;
@@ -25,6 +25,7 @@
 /**
  * <!-- begin-user-doc -->
  * A representation of the model object '<em><b>Structured Classifier</b></em>'.
+ * @extends AttributeOwner
  * <!-- end-user-doc -->
  *
  * <!-- begin-model-doc -->
@@ -47,7 +48,7 @@
  * @generated
  */
 public interface StructuredClassifier
-		extends Classifier {
+		extends Classifier, AttributeOwner {
 
 	/**
 	 * Returns the value of the '<em><b>Owned Attribute</b></em>' containment reference list.
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/util/UMLUtil.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/util/UMLUtil.java
index 3b8fa86..6da8c3d 100644
--- a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/util/UMLUtil.java
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/util/UMLUtil.java
@@ -10,9 +10,9 @@
  *   Kenn Hussey (Embarcadero Technologies) - 199624, 184249, 204406, 208125, 204200, 213218, 213903, 220669, 208016, 226396, 271470
  *   Nicolas Rouquette (JPL) - 260120, 313837
  *   Kenn Hussey - 286329, 313601, 314971, 344907, 236184, 335125
- *   Kenn Hussey (CEA) - 327039, 358792, 364419, 366350, 307343, 382637, 273949, 389542, 389495, 316165, 392833, 399544, 322715, 163556, 212765, 397324, 204658, 408612, 411731
+ *   Kenn Hussey (CEA) - 327039, 358792, 364419, 366350, 307343, 382637, 273949, 389542, 389495, 316165, 392833, 399544, 322715, 163556, 212765, 397324, 204658, 408612, 411731, 269598
  *   Yann Tanguy (CEA) - 350402
- *   Christian W. Damus (CEA) - 392833, 251963
+ *   Christian W. Damus (CEA) - 392833, 251963, 405061
  *
  */
 package org.eclipse.uml2.uml.util;
@@ -73,8 +73,8 @@
 import org.eclipse.uml2.types.TypesFactory;
 import org.eclipse.uml2.types.TypesPackage;
 import org.eclipse.uml2.uml.AggregationKind;
-import org.eclipse.uml2.uml.Artifact;
 import org.eclipse.uml2.uml.Association;
+import org.eclipse.uml2.uml.AttributeOwner;
 import org.eclipse.uml2.uml.Behavior;
 import org.eclipse.uml2.uml.BehavioredClassifier;
 import org.eclipse.uml2.uml.Classifier;
@@ -100,6 +100,7 @@
 import org.eclipse.uml2.uml.OpaqueBehavior;
 import org.eclipse.uml2.uml.OpaqueExpression;
 import org.eclipse.uml2.uml.Operation;
+import org.eclipse.uml2.uml.OperationOwner;
 import org.eclipse.uml2.uml.PackageMerge;
 import org.eclipse.uml2.uml.Parameter;
 import org.eclipse.uml2.uml.ParameterDirectionKind;
@@ -108,10 +109,8 @@
 import org.eclipse.uml2.uml.Profile;
 import org.eclipse.uml2.uml.Property;
 import org.eclipse.uml2.uml.RedefinableElement;
-import org.eclipse.uml2.uml.Signal;
 import org.eclipse.uml2.uml.Stereotype;
 import org.eclipse.uml2.uml.StructuralFeature;
-import org.eclipse.uml2.uml.StructuredClassifier;
 import org.eclipse.uml2.uml.TemplateBinding;
 import org.eclipse.uml2.uml.TemplateParameter;
 import org.eclipse.uml2.uml.TemplateParameterSubstitution;
@@ -2394,6 +2393,8 @@
 		protected static final Pattern ANNOTATION_DETAIL_PATTERN = Pattern
 			.compile("\\s+((?>\\\\.|\\S)+)\\s*+=\\s*((['\"])((?>\\\\.|.)*?)\\3)"); //$NON-NLS-1$
 
+		protected static final String ANNOTATION_DETAIL__ORIGINAL_NAME = "originalName"; //$NON-NLS-1$
+
 		protected static final String OCL_DELEGATE_URI = "http://www.eclipse.org/emf/2002/Ecore/OCL"; //$NON-NLS-1$
 
 		protected final Map<Element, EModelElement> elementToEModelElementMap = new LinkedHashMap<Element, EModelElement>();
@@ -2406,9 +2407,30 @@
 
 		protected Map<Object, Object> context = null;
 
-		protected void setName(ENamedElement eNamedElement, String name,
+		/**
+		 * Sets the {@code name} of a converted element.
+		 * <p>
+		 * As of the 4.2 API version, if the Ecore name differs for any reason
+		 * from the original UML name, it is recorded for
+		 * {@linkplain UMLUtil#getOriginalName(ENamedElement) later retrieval}.
+		 * </p>
+		 * 
+		 * @param eNamedElement
+		 *            the converted Ecore element in which to set a name
+		 * @param name
+		 *            the name to set
+		 * @param validate
+		 *            whether to ensure that the name is a valid Java
+		 *            identifier, munging it if necessary
+		 * 
+		 * @see UMLUtil#getOriginalName(ENamedElement)
+		 * @see UML2Util#getValidJavaIdentifier(String)
+		 */
+		protected void setName(ENamedElement eNamedElement, final String name,
 				boolean validate) {
 
+			String ecoreName = name;
+
 			if (!isEmpty(name)
 				&& options != null
 				&& !OPTION__IGNORE
@@ -2450,19 +2472,13 @@
 				if (OPTION__PROCESS.equals(options
 					.get(OPTION__CAMEL_CASE_NAMES))) {
 
-					eNamedElement.setName(validate
-						? getValidJavaIdentifier(camelCaseName)
-						: camelCaseName);
-				} else {
-					eNamedElement.setName(validate
-						? getValidJavaIdentifier(name)
-						: name);
+					ecoreName = camelCaseName;
 				}
 
 				if (!camelCaseName.equals(name)) {
 
 					if (DEBUG) {
-						System.out.println(name + " -> " + camelCaseNameBuffer); //$NON-NLS-1$
+						System.out.println(name + " -> " + camelCaseName); //$NON-NLS-1$
 					}
 
 					if (OPTION__PROCESS.equals(options
@@ -2498,11 +2514,23 @@
 								new Object[]{eNamedElement}));
 					}
 				}
-			} else {
-				eNamedElement.setName(validate
-					? getValidJavaIdentifier(name)
-					: name);
 			}
+
+			if (validate) {
+				ecoreName = getValidJavaIdentifier(ecoreName);
+			}
+
+			if (!safeEquals(ecoreName, name)) {
+				// record the original name, regardless whether it was converted
+				// by the camel-case names option or by munging to get a valid
+				// Java identifier, because clients such as OCL will require the
+				// traceability
+				EcoreUtil.setAnnotation(eNamedElement,
+					UML2_UML_PACKAGE_2_0_NS_URI,
+					ANNOTATION_DETAIL__ORIGINAL_NAME, name);
+			}
+
+			eNamedElement.setName(ecoreName);
 		}
 
 		protected void setName(ENamedElement eNamedElement,
@@ -2519,6 +2547,40 @@
 			}
 		}
 
+		/**
+		 * Queries the original name (as defined in the source UML model) of the
+		 * given Ecore named element, in the case that the original name was not a
+		 * valid Ecore/Java name and was transformed either via the
+		 * {@link UML2EcoreConverter#OPTION__CAMEL_CASE_NAMES} option or simply
+		 * validating the name.
+		 * 
+		 * @param eNamedElement
+		 *            an Ecore named element
+		 * 
+		 * @return its original name in the UML model in which it was defined, or
+		 *         just its Ecore name if the original name is not recorded or is
+		 *         not different
+		 * 
+		 * @since 4.2
+		 * 
+		 * @see UML2EcoreConverter#setName(ENamedElement, String, boolean)
+		 */
+		public static String getOriginalName(ENamedElement eNamedElement) {
+			String result = eNamedElement.getName();
+
+			EAnnotation annotation = eNamedElement
+				.getEAnnotation(UML2_UML_PACKAGE_2_0_NS_URI);
+			if (annotation != null) {
+				String originalName = annotation.getDetails().get(
+					ANNOTATION_DETAIL__ORIGINAL_NAME);
+				if (originalName != null) {
+					result = originalName;
+				}
+			}
+
+			return result;
+		}
+
 		protected EClassifier getEType(Type type) {
 			EClassifier eType = null;
 
@@ -9745,73 +9807,15 @@
 	}
 
 	protected static EList<Property> getOwnedAttributes(Type type) {
-		return new UMLSwitch<EList<Property>>() {
-
-			@Override
-			public EList<Property> caseArtifact(Artifact artifact) {
-				return artifact.getOwnedAttributes();
-			}
-
-			@Override
-			public EList<Property> caseDataType(DataType dataType) {
-				return dataType.getOwnedAttributes();
-			}
-
-			@Override
-			public EList<Property> caseInterface(Interface interface_) {
-				return interface_.getOwnedAttributes();
-			}
-
-			@Override
-			public EList<Property> caseSignal(Signal signal) {
-				return signal.getOwnedAttributes();
-			}
-
-			@Override
-			public EList<Property> caseStructuredClassifier(
-					StructuredClassifier structuredClassifier) {
-				return structuredClassifier.getOwnedAttributes();
-			}
-
-			@Override
-			public EList<Property> doSwitch(EObject eObject) {
-				return eObject == null
-					? null
-					: super.doSwitch(eObject);
-			}
-		}.doSwitch(type);
+		return type instanceof AttributeOwner
+			? ((AttributeOwner) type).getOwnedAttributes()
+			: null;
 	}
 
 	protected static EList<Operation> getOwnedOperations(Type type) {
-		return new UMLSwitch<EList<Operation>>() {
-
-			@Override
-			public EList<Operation> caseArtifact(Artifact artifact) {
-				return artifact.getOwnedOperations();
-			}
-
-			@Override
-			public EList<Operation> caseClass(org.eclipse.uml2.uml.Class class_) {
-				return class_.getOwnedOperations();
-			}
-
-			@Override
-			public EList<Operation> caseDataType(DataType dataType) {
-				return dataType.getOwnedOperations();
-			}
-
-			@Override
-			public EList<Operation> caseInterface(Interface interface_) {
-				return interface_.getOwnedOperations();
-			}
-
-			@Override
-			public EList<Operation> doSwitch(EObject eObject) {
-				return eObject == null
-					? null
-					: super.doSwitch(eObject);
-			}
-		}.doSwitch(type);
+		return type instanceof OperationOwner
+			? ((OperationOwner) type).getOwnedOperations()
+			: null;
 	}
 
 	protected static EList<ETypeParameter> getETypeParameters(EObject eObject) {
@@ -10901,5 +10905,4 @@
 
 		return false;
 	}
-
 }
diff --git a/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/Bug405061.uml b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/Bug405061.uml
new file mode 100644
index 0000000..a35f0b4
--- /dev/null
+++ b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/Bug405061.uml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Package xmi:version="20110701" xmlns:xmi="http://www.omg.org/spec/XMI/20110701" xmlns:uml="http://www.eclipse.org/uml2/4.0.0/UML" xmi:id="_JyuasDWiEeOonfkTJ1eP9w" name="foo" URI="http://foo">
+  <elementImport xmi:id="_dTZlADWiEeOonfkTJ1eP9w">
+    <importedElement xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#Boolean"/>
+  </elementImport>
+  <elementImport xmi:id="_dTazIDWiEeOonfkTJ1eP9w">
+    <importedElement xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#Integer"/>
+  </elementImport>
+  <elementImport xmi:id="_dTazITWiEeOonfkTJ1eP9w">
+    <importedElement xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#Real"/>
+  </elementImport>
+  <elementImport xmi:id="_dTbaMDWiEeOonfkTJ1eP9w">
+    <importedElement xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#String"/>
+  </elementImport>
+  <elementImport xmi:id="_dTbaMTWiEeOonfkTJ1eP9w">
+    <importedElement xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#UnlimitedNatural"/>
+  </elementImport>
+  <packagedElement xmi:type="uml:Class" xmi:id="_OJx6gDWiEeOonfkTJ1eP9w" name="My Class">
+    <ownedAttribute xmi:id="_SilGwDWiEeOonfkTJ1eP9w" name="Name">
+      <type xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#String"/>
+    </ownedAttribute>
+    <ownedAttribute xmi:id="_iDLG0DWiEeOonfkTJ1eP9w" name="last name">
+      <type xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#String"/>
+    </ownedAttribute>
+    <ownedAttribute xmi:id="_lZOcoDWiEeOonfkTJ1eP9w" name="social_security_no">
+      <type xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#String"/>
+    </ownedAttribute>
+    <ownedAttribute xmi:id="_nQaLQDWjEeOonfkTJ1eP9w" name="not.java$safe">
+      <type xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#String"/>
+    </ownedAttribute>
+    <ownedAttribute xmi:id="_sJjHoDWnEeO_nts5NvuY2w" name="noProblemHere">
+      <type xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#String"/>
+    </ownedAttribute>
+  </packagedElement>
+</uml:Package>
diff --git a/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/Bug405061Test.java b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/Bug405061Test.java
new file mode 100644
index 0000000..89afd7e
--- /dev/null
+++ b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/Bug405061Test.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2013 CEA 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
+ *
+ * Contributors:
+ *   Christian W. Damus (CEA) - initial API and implementation
+ *   
+ */
+package org.eclipse.uml2.uml.bug.tests;
+
+import java.net.URL;
+import java.util.Collection;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.ENamedElement;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.uml2.common.util.UML2Util;
+import org.eclipse.uml2.uml.Class;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Property;
+import org.eclipse.uml2.uml.Stereotype;
+import org.eclipse.uml2.uml.UMLPackage;
+import org.eclipse.uml2.uml.tests.util.StandaloneSupport;
+import org.eclipse.uml2.uml.util.UMLUtil;
+import org.eclipse.uml2.uml.util.UMLUtil.Ecore2UMLConverter;
+import org.eclipse.uml2.uml.util.UMLUtil.UML2EcoreConverter;
+
+/**
+ * Test suite for the changes introduced for Bug 405061.
+ * 
+ * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=405061
+ */
+public class Bug405061Test
+		extends TestCase {
+
+	private ResourceSet rset;
+
+	private Package model;
+
+	private EPackage converted;
+
+	private EClass myClassConverted;
+
+	/**
+	 * Initializes me with my name.
+	 * 
+	 * @param name
+	 *            my name
+	 */
+	public Bug405061Test(String name) {
+		super(name);
+	}
+
+	public static Test suite() {
+		return new TestSuite(Bug405061Test.class, "Bug 405061 tests"); //$NON-NLS-1$
+	}
+
+	public void testInitialCapName() {
+		assertOriginalName("Name",
+			myClassConverted.getEStructuralFeature("name"));
+	}
+
+	public void testWhitespaceName() {
+		assertOriginalName("My Class", myClassConverted);
+		assertOriginalName("last name",
+			myClassConverted.getEStructuralFeature("lastName"));
+	}
+
+	public void testUnderscoreName() {
+		assertOriginalName("social_security_no",
+			myClassConverted.getEStructuralFeature("socialSecurityNo"));
+	}
+
+	public void testInvalidCharName() {
+		assertOriginalName("not.java$safe",
+			myClassConverted.getEStructuralFeature("notjava$safe"));
+	}
+
+	public void testUnmodifiedName() {
+		EStructuralFeature property = myClassConverted
+			.getEStructuralFeature("noProblemHere");
+		assertOriginalName("noProblemHere", property);
+		assertNull("Original name should not have been recorded.",
+			EcoreUtil.getAnnotation(property,
+				UMLUtil.UML2_UML_PACKAGE_2_0_NS_URI,
+				PrivateUML2EcoreConverter.ANNOTATION_DETAIL__ORIGINAL_NAME));
+	}
+
+	public void testValidateButNoCamelCaseOption() {
+		Map<String, String> options = new java.util.HashMap<String, String>();
+		options.put(UML2EcoreConverter.OPTION__CAMEL_CASE_NAMES,
+			UMLUtil.OPTION__IGNORE);
+		EPackage alternative = UMLUtil.convertToEcore(model, options)
+			.iterator().next();
+
+		EClass eClass = (EClass) alternative.getEClassifier("MyClass");
+		assertOriginalName("My Class", eClass);
+		assertOriginalName("Name", eClass.getEStructuralFeature("Name"));
+		assertOriginalName("last name",
+			eClass.getEStructuralFeature("lastname"));
+		assertOriginalName("social_security_no",
+			eClass.getEStructuralFeature("social_security_no"));
+		assertOriginalName("not.java$safe",
+			eClass.getEStructuralFeature("notjava$safe"));
+	}
+
+	public void testOriginalNameAnnotationNotReversedToUML() {
+		Map<String, String> options = new java.util.HashMap<String, String>();
+		options.put(Ecore2UMLConverter.OPTION__ANNOTATION_DETAILS,
+			UMLUtil.OPTION__PROCESS);
+		options.put(Ecore2UMLConverter.OPTION__ECORE_TAGGED_VALUES,
+			UMLUtil.OPTION__PROCESS);
+		Package alternative = UMLUtil.convertFromEcore(converted, options)
+			.iterator().next();
+		Class umlClass = (Class) alternative.getOwnedType("MyClass");
+		assertNotAnnotated(umlClass);
+		for (Property next : umlClass.getOwnedAttributes()) {
+			assertNotAnnotated(next);
+		}
+	}
+
+	//
+	// Test framework
+	//
+
+	@Override
+	protected void setUp()
+			throws Exception {
+
+		rset = new ResourceSetImpl();
+
+		if (StandaloneSupport.isStandalone()) {
+			StandaloneSupport.init(rset);
+		}
+
+		model = getTestModel();
+
+		Map<String, String> options = new java.util.HashMap<String, String>();
+		options.put(UML2EcoreConverter.OPTION__CAMEL_CASE_NAMES,
+			UMLUtil.OPTION__PROCESS);
+		converted = UMLUtil.convertToEcore(model, options).iterator().next();
+		myClassConverted = (EClass) converted.getEClassifier("MyClass");
+		assertNotNull(myClassConverted);
+	}
+
+	@Override
+	protected void tearDown()
+			throws Exception {
+
+		model = null;
+
+		for (Resource next : rset.getResources()) {
+			next.unload();
+		}
+
+		rset.getResources().clear();
+		rset.eAdapters().clear();
+		rset = null;
+	}
+
+	void assertOriginalName(String expectedName, ENamedElement element) {
+		assertEquals(expectedName,
+			UMLUtil.UML2EcoreConverter.getOriginalName(element));
+	}
+
+	void assertNotAnnotated(Element umlElement) {
+		for (Stereotype next : umlElement.getAppliedStereotypes()) {
+			if (UMLUtil.PROFILE__ECORE.equals(next.getProfile().getName())) {
+				assertTrue("element has annotations",
+					((Collection<?>) umlElement.getValue(next,
+						UMLUtil.TAG_DEFINITION__ANNOTATIONS)).isEmpty());
+			}
+		}
+
+		assertTrue("element has annotations", umlElement.getEAnnotations()
+			.isEmpty());
+	}
+
+	Package getTestModel() {
+		URL url = getClass().getResource("Bug405061.uml"); //$NON-NLS-1$
+		return (Package) UML2Util.load(rset,
+			URI.createURI(url.toExternalForm()), UMLPackage.Literals.PACKAGE);
+	}
+
+	protected static class PrivateUML2EcoreConverter
+			extends UMLUtil.UML2EcoreConverter {
+
+		static final String ANNOTATION_DETAIL__ORIGINAL_NAME = UMLUtil.UML2EcoreConverter.ANNOTATION_DETAIL__ORIGINAL_NAME;
+	}
+}
diff --git a/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/UMLBugTests.java b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/UMLBugTests.java
index 70a021a..b1d6a8f 100644
--- a/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/UMLBugTests.java
+++ b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/UMLBugTests.java
@@ -7,7 +7,7 @@
  *
  * Contributors:
  *   Christian W. Damus (CEA) - initial API and implementation
- *   Christian W. Damus (CEA) - 401682
+ *   Christian W. Damus (CEA) - 403365, 300957, 405061, 401682
  */
 package org.eclipse.uml2.uml.bug.tests;
 
@@ -38,8 +38,9 @@
 		result.addTest(Bug392833Test.suite());
 		result.addTest(Bug403365Test.suite());
 		result.addTest(Bug300957Test.suite());
+		result.addTest(Bug405061Test.suite());
 		result.addTest(Bug401682Test.suite());
 
 		return result;
 	}
-}
\ No newline at end of file
+}