[431996] Support Ecore publishing and provide fragment path utilities
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/plugin.properties b/plugins/org.eclipse.emf.codegen.ecore.ui/plugin.properties
index 7fab4da..3bb9deb 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.ui/plugin.properties
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/plugin.properties
@@ -446,3 +446,5 @@
 _UI_GenModel_styleProviders_description = Whether item providers should provide support for specifying styled labels
 _UI_GenModel_cleanup_feature = Cleanup
 _UI_GenModel_cleanup_description = Whether to invoke the configured source clean actions after generating
+_UI_GenPackage_publicationLocation_feature = Publication Location
+_UI_GenPackage_publicationLocation_description = The workspace-relative location at which to generate a published version of the Ecore model resource
diff --git a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenPackageItemProvider.java b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenPackageItemProvider.java
index 81b09ea..0095695 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenPackageItemProvider.java
+++ b/plugins/org.eclipse.emf.codegen.ecore.ui/src/org/eclipse/emf/codegen/ecore/genmodel/provider/GenPackageItemProvider.java
@@ -93,6 +93,7 @@
       addContentTypeIdentifierPropertyDescriptor(object);
       addFileExtensionsPropertyDescriptor(object);
       addEcorePackagePropertyDescriptor(object);
+      addPublicationLocationPropertyDescriptor(object);
     }
     return itemPropertyDescriptors;
   }
@@ -627,6 +628,29 @@
   }
 
   /**
+   * This adds a property descriptor for the Publication Location feature.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  protected void addPublicationLocationPropertyDescriptor(Object object)
+  {
+    itemPropertyDescriptors.add
+      (createItemPropertyDescriptor
+        (((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+         getResourceLocator(),
+         getString("_UI_GenPackage_publicationLocation_feature"),
+         getString("_UI_GenPackage_publicationLocation_description"),
+         GenModelPackage.Literals.GEN_PACKAGE__PUBLICATION_LOCATION,
+         true,
+         false,
+         false,
+         ItemPropertyDescriptor.GENERIC_VALUE_IMAGE,
+         getString("_UI_ModelPropertyCategory"),
+         null));
+  }
+
+  /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
@@ -735,6 +759,7 @@
       case GenModelPackage.GEN_PACKAGE__CONTENT_TYPE_IDENTIFIER:
       case GenModelPackage.GEN_PACKAGE__FILE_EXTENSIONS:
       case GenModelPackage.GEN_PACKAGE__ECORE_PACKAGE:
+      case GenModelPackage.GEN_PACKAGE__PUBLICATION_LOCATION:
         fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true));
         return;
       case GenModelPackage.GEN_PACKAGE__GEN_ENUMS:
diff --git a/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.ecore b/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.ecore
index d80178a..5760f0e 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.ecore
+++ b/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.ecore
@@ -185,6 +185,7 @@
     <eStructuralFeatures xsi:type="ecore:EReference" name="genClassifiers" upperBound="-1"
         eType="#//GenClassifier" changeable="false" volatile="true" transient="true"
         resolveProxies="false" eOpposite="#//GenClassifier/genPackage"/>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="publicationLocation" eType="ecore:EDataType ../../org.eclipse.emf.ecore/model/Ecore.ecore#//EString"/>
   </eClassifiers>
   <eClassifiers xsi:type="ecore:EClass" name="GenClass" eSuperTypes="#//GenClassifier">
     <eStructuralFeatures xsi:type="ecore:EAttribute" name="provider" eType="#//GenProviderKind"/>
diff --git a/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.genmodel b/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.genmodel
index d1d2925..f7c0d53 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.genmodel
+++ b/plugins/org.eclipse.emf.codegen.ecore/model/GenModel.genmodel
@@ -282,6 +282,8 @@
       <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference GenModel.ecore#//GenPackage/genClasses"/>
       <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference GenModel.ecore#//GenPackage/nestedGenPackages"/>
       <genFeatures property="None" notify="false" createChild="false" ecoreFeature="ecore:EReference GenModel.ecore#//GenPackage/genClassifiers"/>
+      <genFeatures createChild="false" propertyCategory="Model" propertyDescription="The workspace-relative location at which to generate a published version of the Ecore model resource"
+          ecoreFeature="ecore:EAttribute GenModel.ecore#//GenPackage/publicationLocation"/>
     </genClasses>
     <genClasses image="false" ecoreClass="GenModel.ecore#//GenClass">
       <genFeatures createChild="false" propertyCategory="Edit" propertyDescription="Whether to generate an item provider and which pattern to use"
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenModelPackage.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenModelPackage.java
index 38cbb25..04fb94a 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenModelPackage.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenModelPackage.java
@@ -1182,13 +1182,22 @@
   int GEN_PACKAGE__GEN_CLASSIFIERS = GEN_BASE_FEATURE_COUNT + 28;
 
   /**
+   * The feature id for the '<em><b>Publication Location</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   * @ordered
+   */
+  int GEN_PACKAGE__PUBLICATION_LOCATION = GEN_BASE_FEATURE_COUNT + 29;
+
+  /**
    * The number of structural features of the '<em>Gen Package</em>' class.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated
    * @ordered
    */
-  int GEN_PACKAGE_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 29;
+  int GEN_PACKAGE_FEATURE_COUNT = GEN_BASE_FEATURE_COUNT + 30;
 
   /**
    * The meta object id for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenClassifierImpl <em>Gen Classifier</em>}' class.
@@ -3267,6 +3276,17 @@
   EReference getGenPackage_GenClassifiers();
 
   /**
+   * Returns the meta object for the attribute '{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getPublicationLocation <em>Publication Location</em>}'.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @return the meta object for the attribute '<em>Publication Location</em>'.
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getPublicationLocation()
+   * @see #getGenPackage()
+   * @generated
+   */
+  EAttribute getGenPackage_PublicationLocation();
+
+  /**
    * Returns the meta object for class '{@link org.eclipse.emf.codegen.ecore.genmodel.GenClass <em>Gen Class</em>}'.
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
@@ -4852,6 +4872,14 @@
     EReference GEN_PACKAGE__GEN_CLASSIFIERS = eINSTANCE.getGenPackage_GenClassifiers();
 
     /**
+     * The meta object literal for the '<em><b>Publication Location</b></em>' attribute feature.
+     * <!-- begin-user-doc -->
+     * <!-- end-user-doc -->
+     * @generated
+     */
+    EAttribute GEN_PACKAGE__PUBLICATION_LOCATION = eINSTANCE.getGenPackage_PublicationLocation();
+
+    /**
      * The meta object literal for the '{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenClassImpl <em>Gen Class</em>}' class.
      * <!-- begin-user-doc -->
      * <!-- end-user-doc -->
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenPackage.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenPackage.java
index 4738666..0b5c3f1 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenPackage.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/GenPackage.java
@@ -56,6 +56,7 @@
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getGenClasses <em>Gen Classes</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getNestedGenPackages <em>Nested Gen Packages</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getGenClassifiers <em>Gen Classifiers</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getPublicationLocation <em>Publication Location</em>}</li>
  * </ul>
  * </p>
  *
@@ -693,6 +694,31 @@
    */
   EList<GenClassifier> getGenClassifiers();
 
+  /**
+   * Returns the value of the '<em><b>Publication Location</b></em>' attribute.
+   * <!-- begin-user-doc -->
+   * <p>
+   * @since 2.10
+   * </p>
+   * <!-- end-user-doc -->
+   * @return the value of the '<em>Publication Location</em>' attribute.
+   * @see #setPublicationLocation(String)
+   * @see org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage#getGenPackage_PublicationLocation()
+   * @model
+   * @generated
+   */
+  String getPublicationLocation();
+
+  /**
+   * Sets the value of the '{@link org.eclipse.emf.codegen.ecore.genmodel.GenPackage#getPublicationLocation <em>Publication Location</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @param value the new value of the '<em>Publication Location</em>' attribute.
+   * @see #getPublicationLocation()
+   * @generated
+   */
+  void setPublicationLocation(String value);
+
   String getInterfacePackageName();
   String getReflectionPackageName();
   String getReflectionClassPackageName();
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/generator/GenPackageGeneratorAdapter.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/generator/GenPackageGeneratorAdapter.java
index e4bfd27..88a03a1 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/generator/GenPackageGeneratorAdapter.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/generator/GenPackageGeneratorAdapter.java
@@ -209,6 +209,7 @@
       (genModel.getModelDirectory(), genPackage, MODEL_PROJECT_TYPE, genModel.isUpdateClasspath(), createMonitor(monitor, 1));
 
     generateSchema(genPackage, monitor);
+    generatePackagePublication(genPackage, monitor);
     generatePackageSerialization(genPackage, monitor);
     generatePackageInterface(genPackage, monitor);
     generatePackageClass(genPackage, monitor);
@@ -237,6 +238,140 @@
     monitor.worked(1);      
   }
 
+  /**
+   * @since 2.10
+   */
+  protected void generatePackagePublication(GenPackage genPackage, Monitor monitor)
+  {
+    String publicationLocation = genPackage.getPublicationLocation();
+    if (publicationLocation != null && !"".equals(publicationLocation))
+    {
+      monitor = createMonitor(monitor, 1);
+
+      try
+      {
+        monitor.beginTask("", 2);
+
+        final GenModel genModel = genPackage.getGenModel();
+        message = CodeGenEcorePlugin.INSTANCE.getString("_UI_GeneratingPackageSerialization_message", new Object[] { publicationLocation });
+        monitor.subTask(message);
+
+        URI targetFile = toURI(publicationLocation);
+        ensureContainerExists(targetFile.trimSegments(1), createMonitor(monitor, 1));
+
+        final ResourceSet originalSet = genModel.eResource().getResourceSet();
+        EPackage originalPackage = genPackage.getEcorePackage();
+
+        ResourceSet outputSet = new ResourceSetImpl();
+        outputSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(Resource.Factory.Registry.DEFAULT_EXTENSION, new EcoreResourceFactoryImpl());
+        URI targetURI = toPlatformResourceURI(targetFile);
+        Resource outputResource = outputSet.createResource(targetURI);
+
+        // Copy the package.
+        EPackage outputPackage = EcoreUtil.copy(originalPackage);
+        outputResource.getContents().add(outputPackage);
+
+        // This URI handler redirects cross-document references to correct schema-location-based or namespace-based values.
+        //
+        XMLResource.URIHandler uriHandler = 
+          new URIHandlerImpl.PlatformSchemeAware()
+          {
+            private EPackage getRootContainingPackage(EObject object)
+            {
+              EPackage result = null;
+              while (object != null)
+              {
+                if (object instanceof EPackage)
+                {
+                  result = (EPackage)object;
+                }
+                object = object.eContainer();
+              }
+              return result;
+            }
+            
+            private EPackage getContainingPackage(EObject object)
+            {
+              while (object != null)
+              {
+                if (object instanceof EPackage)
+                {
+                  return (EPackage)object;
+                }
+                object = object.eContainer();
+              }
+              return null;
+            }
+
+            private URI redirect(URI uri)
+            {
+              if (!uri.isCurrentDocumentReference() && uri.hasFragment())
+              {
+                EObject object = originalSet.getEObject(uri, false);
+                if (object != null)
+                {
+                  EPackage ePackage = getRootContainingPackage(object);
+                  if (ePackage != null)
+                  {
+                    String schemaLocation = EcoreUtil.getAnnotation(ePackage, EcorePackage.eNS_URI, "schemaLocation");
+                    if (schemaLocation != null)
+                    {
+                      return URI.createURI(schemaLocation).appendFragment(uri.fragment());
+                    }
+                    else
+                    {
+                      String relativeURIFragmentPath = EcoreUtil.getRelativeURIFragmentPath(getContainingPackage(object), object);
+                      return URI.createURI(ePackage.getNsURI()).appendFragment("//" + relativeURIFragmentPath);
+                    }
+                  }
+                }
+              }
+              return uri;
+            }
+
+            @Override
+            public URI deresolve(URI uri)
+            {
+              return redirect(uri);
+            }
+
+            @Override
+            public URI resolve(URI uri)
+            {
+              throw new UnsupportedOperationException("There should be no resolving while serializing");
+            }
+
+            @Override
+            public void setBaseURI(URI uri)
+            {
+              baseURI = uri;
+            }
+          };
+        Map<Object, Object> options = new HashMap<Object, Object>();
+        options.put(XMLResource.OPTION_URI_HANDLER, uriHandler);
+        options.put(Resource.OPTION_SAVE_ONLY_IF_CHANGED, Resource.OPTION_SAVE_ONLY_IF_CHANGED_MEMORY_BUFFER);
+        options.put(Resource.OPTION_LINE_DELIMITER, Resource.OPTION_LINE_DELIMITER_UNSPECIFIED);
+
+        try
+        {
+          outputResource.save(options);
+        }
+        catch (IOException exception)
+        {
+          CodeGenEcorePlugin.INSTANCE.log(exception);
+        }
+      }
+      finally
+      {
+        monitor.done();
+      }
+    }
+    else
+    {
+      monitor.worked(1);
+    }
+  }
+
   protected void generatePackageSerialization(GenPackage genPackage, Monitor monitor)
   {
     if (genPackage.hasClassifiers() && genPackage.isLoadingInitialization())
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenModelPackageImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenModelPackageImpl.java
index f380471..19b101f 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenModelPackageImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenModelPackageImpl.java
@@ -1453,6 +1453,16 @@
    * <!-- end-user-doc -->
    * @generated
    */
+  public EAttribute getGenPackage_PublicationLocation()
+  {
+    return (EAttribute)genPackageEClass.getEStructuralFeatures().get(29);
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
   public EClass getGenClass()
   {
     return genClassEClass;
@@ -2185,6 +2195,7 @@
     createEReference(genPackageEClass, GEN_PACKAGE__GEN_CLASSES);
     createEReference(genPackageEClass, GEN_PACKAGE__NESTED_GEN_PACKAGES);
     createEReference(genPackageEClass, GEN_PACKAGE__GEN_CLASSIFIERS);
+    createEAttribute(genPackageEClass, GEN_PACKAGE__PUBLICATION_LOCATION);
 
     genClassEClass = createEClass(GEN_CLASS);
     createEAttribute(genClassEClass, GEN_CLASS__PROVIDER);
@@ -2424,6 +2435,7 @@
     initEReference(getGenPackage_GenClasses(), this.getGenClass(), null, "genClasses", null, 0, -1, GenPackage.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEReference(getGenPackage_NestedGenPackages(), this.getGenPackage(), null, "nestedGenPackages", null, 0, -1, GenPackage.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
     initEReference(getGenPackage_GenClassifiers(), this.getGenClassifier(), this.getGenClassifier_GenPackage(), "genClassifiers", null, 0, -1, GenPackage.class, IS_TRANSIENT, IS_VOLATILE, !IS_CHANGEABLE, !IS_COMPOSITE, !IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
+    initEAttribute(getGenPackage_PublicationLocation(), theEcorePackage.getEString(), "publicationLocation", null, 0, 1, GenPackage.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
 
     initEClass(genClassEClass, GenClass.class, "GenClass", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS);
     initEAttribute(getGenClass_Provider(), this.getGenProviderKind(), "provider", null, 0, 1, GenClass.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED);
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenPackageImpl.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenPackageImpl.java
index 18d01e0..f50b4c8 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenPackageImpl.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenPackageImpl.java
@@ -123,6 +123,7 @@
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenPackageImpl#getGenClasses <em>Gen Classes</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenPackageImpl#getNestedGenPackages <em>Nested Gen Packages</em>}</li>
  *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenPackageImpl#getGenClassifiers <em>Gen Classifiers</em>}</li>
+ *   <li>{@link org.eclipse.emf.codegen.ecore.genmodel.impl.GenPackageImpl#getPublicationLocation <em>Publication Location</em>}</li>
  * </ul>
  * </p>
  *
@@ -623,6 +624,26 @@
   protected EList<GenPackage> nestedGenPackages;
 
   /**
+   * The default value of the '{@link #getPublicationLocation() <em>Publication Location</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getPublicationLocation()
+   * @generated
+   * @ordered
+   */
+  protected static final String PUBLICATION_LOCATION_EDEFAULT = null;
+
+  /**
+   * The cached value of the '{@link #getPublicationLocation() <em>Publication Location</em>}' attribute.
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @see #getPublicationLocation()
+   * @generated
+   * @ordered
+   */
+  protected String publicationLocation = PUBLICATION_LOCATION_EDEFAULT;
+
+  /**
    * <!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated modifiable
@@ -1393,6 +1414,29 @@
    * <!-- end-user-doc -->
    * @generated
    */
+  public String getPublicationLocation()
+  {
+    return publicationLocation;
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
+  public void setPublicationLocation(String newPublicationLocation)
+  {
+    String oldPublicationLocation = publicationLocation;
+    publicationLocation = newPublicationLocation;
+    if (eNotificationRequired())
+      eNotify(new ENotificationImpl(this, Notification.SET, GenModelPackage.GEN_PACKAGE__PUBLICATION_LOCATION, oldPublicationLocation, publicationLocation));
+  }
+
+  /**
+   * <!-- begin-user-doc -->
+   * <!-- end-user-doc -->
+   * @generated
+   */
   @Override
   public NotificationChain eInverseAdd(InternalEObject otherEnd, int featureID, NotificationChain msgs)
   {
@@ -1515,6 +1559,8 @@
         return getNestedGenPackages();
       case GenModelPackage.GEN_PACKAGE__GEN_CLASSIFIERS:
         return getGenClassifiers();
+      case GenModelPackage.GEN_PACKAGE__PUBLICATION_LOCATION:
+        return getPublicationLocation();
     }
     return super.eGet(featureID, resolve, coreType);
   }
@@ -1618,6 +1664,9 @@
         getNestedGenPackages().clear();
         getNestedGenPackages().addAll((Collection<? extends GenPackage>)newValue);
         return;
+      case GenModelPackage.GEN_PACKAGE__PUBLICATION_LOCATION:
+        setPublicationLocation((String)newValue);
+        return;
     }
     super.eSet(featureID, newValue);
   }
@@ -1716,6 +1765,9 @@
       case GenModelPackage.GEN_PACKAGE__NESTED_GEN_PACKAGES:
         getNestedGenPackages().clear();
         return;
+      case GenModelPackage.GEN_PACKAGE__PUBLICATION_LOCATION:
+        setPublicationLocation(PUBLICATION_LOCATION_EDEFAULT);
+        return;
     }
     super.eUnset(featureID);
   }
@@ -1788,6 +1840,8 @@
         return nestedGenPackages != null && !nestedGenPackages.isEmpty();
       case GenModelPackage.GEN_PACKAGE__GEN_CLASSIFIERS:
         return !getGenClassifiers().isEmpty();
+      case GenModelPackage.GEN_PACKAGE__PUBLICATION_LOCATION:
+        return PUBLICATION_LOCATION_EDEFAULT == null ? publicationLocation != null : !PUBLICATION_LOCATION_EDEFAULT.equals(publicationLocation);
     }
     return super.eIsSet(featureID);
   }
@@ -1847,6 +1901,8 @@
     result.append(contentTypeIdentifier);
     result.append(", fileExtensions: ");
     result.append(fileExtensions);
+    result.append(", publicationLocation: ");
+    result.append(publicationLocation);
     result.append(')');
     return result.toString();
   }
@@ -4052,6 +4108,8 @@
     }
 
     reconcileGenAnnotations(oldGenPackageVersion);
+
+    setPublicationLocation(oldGenPackageVersion.getPublicationLocation());
   }
 
   public boolean reconcile()
diff --git a/plugins/org.eclipse.emf.ecore.xmi/src/org/eclipse/emf/ecore/xmi/impl/XMLHandler.java b/plugins/org.eclipse.emf.ecore.xmi/src/org/eclipse/emf/ecore/xmi/impl/XMLHandler.java
index c9d9d13..aaadacc 100644
--- a/plugins/org.eclipse.emf.ecore.xmi/src/org/eclipse/emf/ecore/xmi/impl/XMLHandler.java
+++ b/plugins/org.eclipse.emf.ecore.xmi/src/org/eclipse/emf/ecore/xmi/impl/XMLHandler.java
@@ -2567,10 +2567,7 @@
         else
         {
           List<EObject> contents = resource.getContents();
-          if (!contents.isEmpty())
-          {
-            content = contents.get(0);
-          }
+          content = EcoreUtil.getObjectsByType(contents, EcorePackage.Literals.EPACKAGE);
         }
 
         if (content instanceof EPackage)
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreUtil.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreUtil.java
index 60dead2..b4a9903 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreUtil.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/util/EcoreUtil.java
@@ -37,6 +37,7 @@
 import org.eclipse.emf.common.util.Diagnostic;
 import org.eclipse.emf.common.util.ECollections;
 import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.SegmentSequence;
 import org.eclipse.emf.common.util.TreeIterator;
 import org.eclipse.emf.common.util.URI;
 import org.eclipse.emf.ecore.EAnnotation;
@@ -2967,9 +2968,9 @@
   /**
    * Returns a URI for the eObject, 
    * i.e., either 
-   * the eProxyURI,
-   * the URI of the eResource with the fragment produced by the eResource,
-   * or the URI consisting of just the fragment that would be produced by a default Resource 
+   * the {@link InternalEObject#eProxyURI() proxy URI},
+   * the URI of the {@link EObject#eResource() resource} with the {@link Resource#getURIFragment(EObject) fragment} produced by the resource,
+   * or the URI consisting of just the {@link #getRelativeURIFragmentPath(EObject, EObject) fragment path} that would be produced by a default Resource 
    * with the eObject as its only contents.
    * @param eObject the object for which to get the URI.
    * @return the URI for the object.
@@ -3003,29 +3004,93 @@
         }
         else
         {
-          InternalEObject internalEObject = (InternalEObject)eObject;
-          List<String> uriFragmentPath = new ArrayList<String>();
-          HashSet<InternalEObject> visited = new HashSet<InternalEObject>();
-          for (InternalEObject container = internalEObject.eInternalContainer(); container != null && visited.add(container); container = internalEObject.eInternalContainer())
-          {
-            uriFragmentPath.add(container.eURIFragmentSegment(internalEObject.eContainingFeature(), internalEObject));
-            internalEObject = container;
-          }
-      
-          StringBuffer result = new StringBuffer("#//");
-      
-          for (int i = uriFragmentPath.size() - 1; i >= 0; --i)
-          {
-            result.append('/');
-            result.append(uriFragmentPath.get(i));
-          }
-          return URI.createURI(result.toString());
+          return URI.createURI("#//" + getRelativeURIFragmentPath(null, eObject, false));
         }
       }
     }
   }
 
   /**
+   * Returns the fragment path of the descendant object relative to its {@link #isAncestor(EObject, EObject) ancestor}.
+   * The ancestor may be <code>null</code>, it which case the path is relative to the {@link #getRootContainer(EObject) root}.
+   * Otherwise, the resulting fragment path can be passed to {@link #getEObject(EObject, String)} along with the ancestor to the yield the descendant.
+   * @param ancestorEObject the ancestor of the descendant object (can be null)
+   * @param descendantEObject  descendant of the ancestor object
+   * @return the relativefragment path.
+   * @see InternalEObject#eURIFragmentSegment(EStructuralFeature, EObject)
+   * @see #getEObject(EObject, String)
+   * @throws IllegalArgumentException if the ancestor is non-null and is not an ancestor of the descendant.
+   * @since 2.10
+   */
+  public static String getRelativeURIFragmentPath(EObject ancestorEObject, EObject descendantEObject)
+  {
+    return getRelativeURIFragmentPath(ancestorEObject, descendantEObject, true);
+  }
+
+  private  static String getRelativeURIFragmentPath(EObject ancestorEObject, EObject descendantEObject, boolean resolve)
+  {
+    if (ancestorEObject == descendantEObject)
+    {
+      return "";
+    }
+
+    List<String> uriFragmentPath = new ArrayList<String>();
+    HashSet<InternalEObject> visited = new HashSet<InternalEObject>();
+    InternalEObject internalEObject = (InternalEObject)descendantEObject;
+    for (InternalEObject container = resolve ? (InternalEObject)internalEObject.eContainer() : internalEObject.eInternalContainer(); 
+         container != null && visited.add(container);
+         container = resolve ? (InternalEObject)internalEObject.eContainer() : internalEObject.eInternalContainer())
+    {
+      uriFragmentPath.add(container.eURIFragmentSegment(internalEObject.eContainingFeature(), internalEObject));
+      internalEObject = container;
+      if (container == ancestorEObject)
+      {
+        break;
+      }
+    }
+    
+    if (internalEObject != ancestorEObject)
+    {
+      throw new IllegalArgumentException("The ancestor '" + ancestorEObject + "' is not an ancestor of '" + descendantEObject + "'");
+    }
+
+    StringBuilder result = new StringBuilder();
+    int size = uriFragmentPath.size();
+    if (size > 0)
+    {
+      for (int i = uriFragmentPath.size() - 1; i > 0; --i)
+      {
+        result.append(uriFragmentPath.get(i));
+        result.append('/');
+      }
+    }
+    result.append(uriFragmentPath.get(0));
+
+    return result.toString();
+  }
+
+  /**
+   * Returns the object reached via by navigating the relative URI fragment path.
+   * @param rootEObject
+   * @param relativeFragmentPath
+   * @return the object at the path.
+   * @see #getRelativeURIFragmentPath(EObject, EObject)
+   * @see InternalEObject#eObjectForURIFragmentSegment(String)
+   * @since 2.10
+   */
+  public static EObject getEObject(EObject rootEObject, String relativeFragmentPath)
+  {
+    String[] segments = SegmentSequence.create("/", relativeFragmentPath).segments();
+    int size = segments.length;
+    EObject eObject = rootEObject;
+    for (int i = 0; i < size && eObject != null; ++i)
+    {
+      eObject = ((InternalEObject)eObject).eObjectForURIFragmentSegment(segments[i]);
+    }
+    return eObject;
+  }
+
+  /**
    * Searches for the first occurrence of the given argument in list starting from
    * a specified index.  The equality is tested using the operator <tt>==<tt> and
    * the <tt>equals</tt> method.