Commit d8369360 authored by Stephan Eberle's avatar Stephan Eberle
Browse files

RESOLVED - bug 531560: Provide better control over schema locations

being added to serialized model files
https://bugs.eclipse.org/bugs/show_bug.cgi?id=531560
parent 576448ee
Loading
Loading
Loading
Loading
+116 −101

File changed.

Preview size limit exceeded, changes collapsed.

+16 −7
Original line number Diff line number Diff line
/**
 * <copyright>
 *
 * Copyright (c) 2008-2016 See4sys, itemis and others.
 * Copyright (c) 2008-2018 See4sys, itemis 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
@@ -17,12 +17,14 @@
 *     itemis - [460260] Expanded paths are collapsed on resource reload
 *     itemis - [485407] Enable eager post-load proxy resolution to support manifold URI fragments referring to the same object
 *     itemis - [501108] The tree viewer state restoration upon Eclipse startup not working for model elements being added after the loading of the underlying has been finished
 *     itemis - [531560] Provide better control over schema locations being added to serialized model files
 *
 * </copyright>
 */
package org.eclipse.sphinx.emf.resource;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -146,12 +148,11 @@ public class ExtendedResourceAdapter extends AdapterImpl implements ExtendedReso
		if (getDefaultLoadOptions().get(ExtendedResource.OPTION_UNLOAD_MEMORY_OPTIMIZED) == Boolean.TRUE) {
			// Turn unloaded eObject into a proxy using an as short as possible dummy URI
			/*
			 * !! Important Note !! Setting the regular full proxy URI would take way too much memory and is generally
			 * useless when the complete ResourceSet, or a self-contained set of resources with no outgoing and incoming
			 * cross-document references gets unloaded (which typically happens when a project or the entire workbench
			 * is closed). However, we must leave an as short as possible dummy URI in place to make sure that clients
			 * which access the unloaded eObject for whatever reason subsequently don't end up considering it a regular
			 * eObject that is still loaded.
			 * !! Important Note !! Setting the regular full proxy URI would take way too much memory and is generally useless when
			 * the complete ResourceSet, or a self-contained set of resources with no outgoing and incoming cross-document
			 * references gets unloaded (which typically happens when a project or the entire workbench is closed). However, we must
			 * leave an as short as possible dummy URI in place to make sure that clients which access the unloaded eObject for
			 * whatever reason subsequently don't end up considering it a regular eObject that is still loaded.
			 */
			((InternalEObject) eObject).eSetProxyURI(EMPTY_URI);
		} else {
@@ -351,6 +352,14 @@ public class ExtendedResourceAdapter extends AdapterImpl implements ExtendedReso
		}
	}

	/*
	 * @see org.eclipse.sphinx.emf.resource.ExtendedResource#getSchemaLocationEntries(java.util.Map)
	 */
	@Override
	public Map<String, String> getSchemaLocationEntries(Map<?, ?> options) {
		return Collections.emptyMap();
	}

	/*
	 * @see org.eclipse.sphinx.emf.resource.ExtendedResource#trimProxyContextInfo(org.eclipse.emf.common.util.URI)
	 */
+184 −154
Original line number Diff line number Diff line
/**
 * <copyright>
 *
 * Copyright (c) 2008-2010 See4sys and others.
 * Copyright (c) 2008-2018 See4sys, itemis 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
@@ -9,6 +9,7 @@
 *
 * Contributors:
 *     See4sys - Initial API and implementation
 *     itemis - [531560] Provide better control over schema locations being added to serialized model files
 *
 * </copyright>
 */
@@ -19,6 +20,7 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -60,6 +62,8 @@ public class ExtendedXMLSaveImpl extends XMLSaveImpl {
	 */
	protected Map<?, ?> options;

	protected ExtendedResource extendedResource;

	protected IModelConverter converter;

	/*
@@ -108,6 +112,7 @@ public class ExtendedXMLSaveImpl extends XMLSaveImpl {
			return;
		}
		xmlResource = resource;
		extendedResource = ExtendedResourceAdapterFactory.INSTANCE.adapt(xmlResource);
		init(resource, options);
		converter = ModelConverterRegistry.INSTANCE.getSaveConverter(xmlResource, options);

@@ -181,10 +186,34 @@ public class ExtendedXMLSaveImpl extends XMLSaveImpl {
		StringBuffer xsiSchemaLocation = buffer;
		String xsiNoNamespaceSchemaLocation = null;
		if (declareSchemaLocation) {
			// Schema location entries defined by resource?
			Map<String, String> schemaLocationEntries = extendedResource != null ? extendedResource.getSchemaLocationEntries(options)
					: Collections.<String, String> emptyMap();
			if (schemaLocationEntries != null && !schemaLocationEntries.isEmpty()) {
				declareXSI = true;

				// Write schema location value string from resource-defined schema location entries
				for (Map.Entry<String, String> entry : schemaLocationEntries.entrySet()) {
					String namespace = entry.getKey();
					String location = entry.getValue();
					URI locationURI = URI.createURI(location);
					if (namespace == null) {
						xsiNoNamespaceSchemaLocation = helper.deresolve(locationURI).toString();
					} else {
						if (xsiSchemaLocation.length() > 0) {
							xsiSchemaLocation.append(' ');
						}
						xsiSchemaLocation.append(namespace);
						xsiSchemaLocation.append(' ');
						xsiSchemaLocation.append(helper.deresolve(locationURI).toString());
					}
				}
			} else {
				Map<String, String> handledBySchemaLocationMap = new HashMap<String, String>();
				@SuppressWarnings("unchecked")
				Map<String, String> schemaLocationCatalog = (Map<String, String>) options.get(ExtendedResource.OPTION_SCHEMA_LOCATION_CATALOG);

				// Write schema location value string from recorded schema location entries
				if (extendedMetaData != null) {
					Resource resource = helper.getResource();
					if (resource != null && resource.getContents().size() >= 1) {
@@ -195,7 +224,6 @@ public class ExtendedXMLSaveImpl extends XMLSaveImpl {
							@SuppressWarnings("unchecked")
							EMap<String, String> xsiSchemaLocationMap = (EMap<String, String>) schemaLocationRoot.eGet(xsiSchemaLocationMapFeature);
							if (!xsiSchemaLocationMap.isEmpty()) {
							// Write schema location value string from recorded schema location entries
								handledBySchemaLocationMap = new HashMap<String, String>(xsiSchemaLocationMap.map());
								for (Map.Entry<String, String> entry : xsiSchemaLocationMap.entrySet()) {
									String namespace = entry.getKey();
@@ -227,14 +255,15 @@ public class ExtendedXMLSaveImpl extends XMLSaveImpl {
																"Schema location catalog entry for namespace '" + namespace + "' is missing")); //$NON-NLS-1$ //$NON-NLS-2$
													}
												} else {
												PlatformLogUtil.logAsWarning(Activator.getPlugin(), new RuntimeException(
														"Schema location catalog is missing")); //$NON-NLS-1$
													PlatformLogUtil.logAsWarning(Activator.getPlugin(),
															new RuntimeException("Schema location catalog is missing")); //$NON-NLS-1$
												}
											}
										} else {
											// Current schema namespace corresponding to a metamodel version that is an
											// older version of the metamodel behind schema location root?
										IMetaModelDescriptor mmDescriptor = MetaModelDescriptorRegistry.INSTANCE.getDescriptor(schemaLocationRoot);
											IMetaModelDescriptor mmDescriptor = MetaModelDescriptorRegistry.INSTANCE
													.getDescriptor(schemaLocationRoot);
											if (mmDescriptor != null) {
												boolean compatible = false;
												for (java.net.URI compatibleNsURI : mmDescriptor.getCompatibleNamespaceURIs()) {
@@ -294,13 +323,14 @@ public class ExtendedXMLSaveImpl extends XMLSaveImpl {
								// Retrieve schema location corresponding to no namespace from schema location catalog
								xsiNoNamespaceSchemaLocation = schemaLocationCatalog.get(null);
								if (xsiNoNamespaceSchemaLocation == null) {
								PlatformLogUtil.logAsWarning(Activator.getPlugin(), new RuntimeException(
										"Schema location catalog entry for no namespace (null) is missing")); //$NON-NLS-1$ 
									PlatformLogUtil.logAsWarning(Activator.getPlugin(),
											new RuntimeException("Schema location catalog entry for no namespace (null) is missing")); //$NON-NLS-1$
								}
							} else {
								xsiNoNamespaceSchemaLocation = helper.getHREF(ePackage);
								if (xsiNoNamespaceSchemaLocation != null && xsiNoNamespaceSchemaLocation.endsWith("#/")) { //$NON-NLS-1$
								xsiNoNamespaceSchemaLocation = xsiNoNamespaceSchemaLocation.substring(0, xsiNoNamespaceSchemaLocation.length() - 2);
									xsiNoNamespaceSchemaLocation = xsiNoNamespaceSchemaLocation.substring(0,
											xsiNoNamespaceSchemaLocation.length() - 2);
								}
							}

@@ -330,8 +360,8 @@ public class ExtendedXMLSaveImpl extends XMLSaveImpl {
									// catalog
									location = schemaLocationCatalog.get(namespace);
									if (location == null) {
									PlatformLogUtil.logAsWarning(Activator.getPlugin(), new RuntimeException(
											"Schema location catalog entry for namespace '" + namespace + "' is missing")); //$NON-NLS-1$ //$NON-NLS-2$
										PlatformLogUtil.logAsWarning(Activator.getPlugin(),
												new RuntimeException("Schema location catalog entry for namespace '" + namespace + "' is missing")); //$NON-NLS-1$ //$NON-NLS-2$
									}
								} else {
									location = helper.getHREF(ePackage);
@@ -363,6 +393,7 @@ public class ExtendedXMLSaveImpl extends XMLSaveImpl {
					}
				}
			}
		}

		for (EPackage ePackage : packages) {
			if (ePackage != noNamespacePackage && ePackage != XMLNamespacePackage.eINSTANCE
@@ -454,9 +485,8 @@ public class ExtendedXMLSaveImpl extends XMLSaveImpl {
	}

	/**
	 * Writes out the contents of the special feature ExtendedResourceConstants.OUTER_CONTENT_ATTRIBUTE_NAME of the
	 * passed in object. This method is used to write out such comment before the starting tag of the actual root
	 * element.
	 * Writes out the contents of the special feature ExtendedResourceConstants.OUTER_CONTENT_ATTRIBUTE_NAME of the passed
	 * in object. This method is used to write out such comment before the starting tag of the actual root element.
	 *
	 * @param top
	 *            The {@link EObject root object} whose mixed outer content (text, comments, CDATA and processing