blob: 794c3078396eb6d26beceb62c3f356eb368cd893 [file] [log] [blame]
/**
* <copyright>
*
* 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 v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
* See4sys - Initial API and implementation
* itemis - [409510] Enable resource scope-sensitive proxy resolutions without forcing metamodel implementations to subclass EObjectImpl
* itemis - [427461] Add progress monitor to resource load options (useful for loading large models)
* itemis - [434954] Hook for overwriting conversion of EMF Diagnostics to IMarkers
* itemis - [442342] Sphinx doen't trim context information from proxy URIs when serializing proxyfied cross-document references
* itemis - [458862] Navigation from problem markers in Check Validation view to model editors and Model Explorer view broken
* 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.Map;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl;
import org.eclipse.sphinx.emf.internal.messages.Messages;
import org.eclipse.sphinx.emf.metamodel.IMetaModelDescriptor;
import org.eclipse.sphinx.emf.scoping.IResourceScope;
/**
* A set of additional services for EMF {@link Resource resources} including memory-optimized unloading, proxy creation
* with custom URI formats, and caching of problem marker attributes.
*/
public interface ExtendedResource {
/**
* Special character signaling the end of the scheme of an URI.
*/
String URI_SCHEME_SEPARATOR = ":"; //$NON-NLS-1$
/**
* Special character separating individual segments within an URI.
*/
String URI_SEGMENT_SEPARATOR = "/"; //$NON-NLS-1$
/**
* Special character signaling the start of the query of an URI.
*/
String URI_QUERY_SEPARATOR = "?"; //$NON-NLS-1$
/**
* Special character separating a keys/value pairs within the query of an URI.
*/
String URI_QUERY_FIELD_SEPARATOR = "&"; //$NON-NLS-1$
/**
* Special character separating keys from values within keys/value pairs in the query of an URI.
*/
String URI_QUERY_KEY_VALUE_SEPARATOR = "="; //$NON-NLS-1$
/**
* Special character signaling the start of the fragment of an URI.
*/
String URI_FRAGMENT_SEPARATOR = "#"; //$NON-NLS-1$
// Regular expression in clear text: ([^&^=]+)=?([^&^=]*)
Pattern URI_QUERY_FIELD_PATTERN = Pattern.compile("([^" + URI_QUERY_FIELD_SEPARATOR + "^" + URI_QUERY_KEY_VALUE_SEPARATOR + "]+)=?([^" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ URI_QUERY_FIELD_SEPARATOR + "^" + URI_QUERY_KEY_VALUE_SEPARATOR + "]*)"); //$NON-NLS-1$ //$NON-NLS-2$
int URI_QUERY_FIELD_PATTERN_KEY_GROUP_IDX = 1;
int URI_QUERY_FIELD_PATTERN_VALUE_GROUP_IDX = 2;
/**
* Used for indicating the {@link IMetaModelDescriptor version} of specified {@link Resource resource}. Can be either
* identical with the {@link IMetaModelDescriptor version} of the metamodel behind the resource content or one of the
* {@link IMetaModelDescriptor#getCompatibleResourceVersionDescriptors() resource version descriptors that are
* compatible with the metamodel version}.
*/
String OPTION_RESOURCE_VERSION_DESCRIPTOR = "RESOURCE_VERSION_DESCRIPTOR"; //$NON-NLS-1$
/**
* Specifies whether to use context-aware proxy URIs when creating proxy objects or not. The default of this option is
* <code>Boolean.TRUE</code> .
*/
String OPTION_USE_CONTEXT_AWARE_PROXY_URIS = "USE_CONTEXT_AWARE_PROXY_URIS"; //$NON-NLS-1$
/**
* Specifies the target {@link IMetaModelDescriptor metamodel descriptor} identifier for this resource.
*/
String OPTION_TARGET_METAMODEL_DESCRIPTOR_ID = "TARGET_METAMODEL_DESCRIPTOR_ID"; //$NON-NLS-1$
/**
* Specifies a string to string map with namespace and system identifier pairs that are allowed to be written in the
* resource's xsi:schemaLocation/xsi:noNamespaceSchemaLocation during saving. Implies that
* {@link XMLResource#OPTION_SCHEMA_LOCATION} is enabled and requires that {@link ExtendedXMLSaveImpl} or
* {@link ExtendedXMISaveImpl}, or a subtype of them, is used as {@link XMLResourceImpl#createXMLSave() serializer} for
* this resource.
*
* @see XMLResource#OPTION_SCHEMA_LOCATION
* @see XMLResourceImpl#createXMLSave()
* @see ExtendedXMLSaveImpl#addNamespaceDeclarations()
* @see ExtendedXMISaveImpl
*/
String OPTION_SCHEMA_LOCATION_CATALOG = "SCHEMA_LOCATION_CATALOG"; //$NON-NLS-1$
/**
* Specifies weather the resource should be validated with a schema during loading. Requires that
* {@link ExtendedXMLLoadImpl} or {@link ExtendedXMILoadImpl}, or a subtype of them, is used as
* {@link XMLResourceImpl#createXMLLoad() loader} for this resource. The default of this option is
* <code>Boolean.FALSE</code>.
* <p>
* The schema used for validation is expected to be defined by a xsi:schemaLocation or xsi:noNamespaceSchemaLocation
* attribute on the resource's root element. The default strategy for retrieving the schema is to resolve the schema
* location system identifier relative to the resource's URI. Other resolution strategies can be supported by providing
* a {@link SchemaLocationURIHandler} as {@link XMLResource#OPTION_URI_HANDLER} as load option. In the latter case it is
* recommended to provide an adequately initialized {@link #OPTION_RESOURCE_VERSION_DESCRIPTOR} along with that. It
* enables the {@link SchemaLocationURIHandler} to resolve unknown schema location system identifiers by falling back to
* a known system identifier corresponding to the resource's {@link IMetaModelDescriptor#getNamespace() namespace}.
* </p>
*
* @see XMLResource#OPTION_URI_HANDLER
* @see SchemaLocationURIHandler
* @see XMLResourceImpl#createXMLLoad()
* @see ExtendedXMLLoadImpl
* @see ExtendedXMILoadImpl
*/
String OPTION_ENABLE_SCHEMA_VALIDATION = "ENABLE_SCHEMA_VALIDATION"; //$NON-NLS-1$
/**
* Specifies a {@link IResourceProblemMarkerFactory resource problem marker factory} that is used to convert the
* {@link Resource#getErrors() errors} and {@link Resource#getWarnings() warnings} on this resource to problem markers
* on underlying {@link IFile} after this resource has been loaded or saved.
*
* @see IResourceProblemMarkerFactory
* @see Resource#getErrors()
* @see Resource#getWarnings()
*/
String OPTION_PROBLEM_MARKER_FACTORY = "PROBLEM_MARKER_FACTORY"; //$NON-NLS-1$
/**
* Specifies the maximum number of {@link Resource#getErrors() errors} and {@link Resource#getWarnings() warnings} on
* this resource that are to be converted to problem markers on underlying {@link IFile} after this resource has been
* loaded or saved. May be an arbitrary positive integer value or {@link #OPTION_MAX_PROBLEM_MARKER_COUNT_UNLIMITED} .
* The default is <code>{@link #OPTION_MAX_PROBLEM_MARKER_COUNT_DEFAULT}</code>.
* <p>
* Note that a high number of problem markers being generated for many files may have a negative impact on overall load
* and save performance.
* <p>
*
* @see Resource#getErrors()
* @see Resource#getWarnings()
*/
String OPTION_MAX_PROBLEM_MARKER_COUNT = "MAX_PROBLEM_MARKER_COUNT"; //$NON-NLS-1$
Integer OPTION_MAX_PROBLEM_MARKER_COUNT_DEFAULT = 10;
Integer OPTION_MAX_PROBLEM_MARKER_COUNT_UNLIMITED = -1;
/**
* Specifies the format string to be used for creating problem marker messages for XML well-formedness problems. Should
* include substitution location (<code>{0}</code>) where the actual problem message can be inserted. The default is
* {@link #OPTION_XML_WELLFORMEDNESS_PROBLEM_FORMAT_STRING_DEFAULT}.
*/
String OPTION_XML_WELLFORMEDNESS_PROBLEM_FORMAT_STRING = "XML_WELLFORMEDNESS_PROBLEM_FORMAT_STRING"; //$NON-NLS-1$
String OPTION_XML_WELLFORMEDNESS_PROBLEM_FORMAT_STRING_DEFAULT = Messages.msg_xmlWellformednessProblemFormatString;
/**
* Specifies the format string to be used for creating problem marker messages for XML validity problems. The default is
* {@link #OPTION_XML_VALIDITY_PROBLEM_FORMAT_STRING_DEFAULT}.
*/
String OPTION_XML_VALIDITY_PROBLEM_FORMAT_STRING = "XML_VALIDITY_PROBLEM_FORMAT_STRING"; //$NON-NLS-1$
String OPTION_XML_VALIDITY_PROBLEM_FORMAT_STRING_DEFAULT = Messages.msg_xmlValidityProblemFormatString;
/**
* Specifies the severity to be used for reporting XML validity problems. May be one of {@link IMarker#SEVERITY_ERROR},
* {@link IMarker#SEVERITY_WARNING}, {@link IMarker#SEVERITY_INFO} or undefined. The default is undefined.
*/
String OPTION_XML_VALIDITY_PROBLEM_SEVERITY = "XML_VALIDITY_PROBLEM_SEVERITY"; //$NON-NLS-1$
/**
* Specifies whether unloading of this resource is to be performed in a limited but memory-optimized way. Requires that
* the resource's {@link ResourceImpl#unloaded(InternalEObject) unloaded(InternalEObject)} method is overridden and
* delegates to {@link ExtendedResourceAdapter#unloaded(EObject)}. The default of this option is
* <code>Boolean.FALSE</code>.
* <p>
* This option involves the following behavioral modifications wrt to regular
* {@link ResourceImpl#unloaded(InternalEObject) unload strategy}:
* <ul>
* <li>Suppression of proxy creation for unloaded {@link EObject}s (for saving non negligible amounts of memory
* consumption for proxy URIs required otherwise)</li>
* <li>Clearing all fields on unloaded {@link EObject}s (to make sure that they get garbage collected as fast as
* possible)</li>
* </ul>
* </p>
* <p>
* Note that this kind of unload is not appropriate under all circumstances. More specifically, it must not be used when
* a resource is to be reloaded (lazily or eagerly). In this case proxies are needed for being able to resolve incoming
* cross-document references from other resources. However, when the complete ResourceSet is unloaded, or a
* self-contained set of resources with no outgoing and incoming cross-document references (which typically happens when
* a project or the entire workbench is closed), proxies are not needed and not creating them can reduce memory
* consumption quite dramatically.
* <p>
*
* @see ResourceImpl#unloaded()
*/
String OPTION_UNLOAD_MEMORY_OPTIMIZED = "UNLOAD_MEMORY_OPTIMIZED"; //$NON-NLS-1$
/**
* Specifies the {@link IProgressMonitor progress monitor} to be used for monitoring the progress and allow for
* cancellation while a {@link Resource resource} is being loaded.
*/
String OPTION_PROGRESS_MONITOR = "PROGRESS_MONITOR"; //$NON-NLS-1$
String OPTION_RECORD_LINE_AND_COLUMN_NUMBERS = "OPTION_RECORD_LINE_AND_COLUMN_NUMBERS"; //$NON-NLS-1$
String LINE_NUMBER_KEY_NAME = "lineNumber"; //$NON-NLS-1$
String COLUMN_NUMBER_KEY_NAME = "columnNumber"; //$NON-NLS-1$
/**
* Returns the map of options that, in addition to the overriding options specified during load, are used to to control
* load behavior.
*/
Map<Object, Object> getDefaultLoadOptions();
/**
* Returns the map of options that, in addition to the overriding options specified during save, are used to to control
* save behavior.
*/
Map<Object, Object> getDefaultSaveOptions();
/**
* Returns the map of options that are used to control the handling of problems encountered while the {@link Resource
* resource} has been loaded or saved.
*/
Map<Object, Object> getProblemHandlingOptions();
/**
* Indicates if the underlying {@link Resource resource} has been fully loaded. By default, this is the case when
* {@link Resource#isLoaded()} returns <code>true</code>.
* <p>
* Custom {@link ExtendedResource} implementations may override this method and adapt its behavior to take additional
* aspects into account, e.g., the completion state of asynchronously performed post load operations or communication
* processes running in the background.
* </p>
*
* @return <code>true</code> if the underlying resource has been fully loaded, <code>false</code> otherwise.
*/
boolean isFullyLoaded();
/**
* Improved implementation of org.eclipse.emf.ecore.resource.impl.ResourceImpl#unloaded(InternalEObject) enabling
* memory-optimized unloading of {@link Resource resource}s and proxy creation with custom {@link URI} formats during
* regular unload.
*
* @param internalEObject
* The {@link InternalEObject} that has just been removed from the resource and is to be further processed by
* this method.
* @see #OPTION_UNLOAD_MEMORY_OPTIMIZED
* @see #getURI(InternalEObject)
*/
void unloaded(EObject eObject);
/**
* Returns the {@link URI} representing given {@link EObject object}.
*
* @param eObject
* The object to be handled.
* @return The URI representing the provided object.
*/
URI getURI(EObject eObject);
/**
* Returns the {@link URI} representing given {@link EObject object}. The resulting URI can optionally be resolved
* against the URI of the resource which contains the object in question.
*
* @param eObject
* The object to be handled.
* @param resolve
* Indicates whether the object's URI should be resolved against the URI of the resource which contains the
* provided model object. This is useful is cases where the native model object URI evaluates in some sort of
* fragment-based URI which does not contain any information about the resource that contains the model
* object (e.g., hb:/#//MyComponent/MyParameterValue). By setting resolve to true, such fragment-based URIs
* will be automatically expanded to a URI that starts with the URI of the model object's resource and is
* followed by the fragment of the model object's native URI (e.g.,
* platform:/resource/MyProject/MyResource/#//MyComponent/MyParameterValue).
* @return The URI representing the provided object.
*/
URI getURI(EObject eObject, boolean resolve);
/**
* Returns the {@link URI} representing given {@link EObject object}. If the object is removed (i.e., not contained in
* any {@link Resource resource}) its URI is determined by appending the URI fragment segments obtained from the removed
* object and its potential direct and indirect removed containers to the base URI obtained from the provided
* {@link EObject old owner} and {@link EStructuralFeature old feature}. If the object is still contained in a resource
* its URI is computed as usual and the old owner and old feature are ignored.
*
* @param oldOwner
* The owner object that is assumed to having contained the given object before it was removed.
* @param oldFeature
* The feature through which the old owner did contain the given object before it was removed.
* @param eObject
* The object to be handled.
* @return The URI representing the provided object.
*/
URI getURI(EObject oldOwner, EStructuralFeature oldFeature, EObject eObject);
/**
* Returns the {@link URI} representing given {@link EObject object}. If the object is removed (i.e., not contained in
* any {@link Resource resource}) its URI is determined by appending the URI fragment segments obtained from the removed
* object and its potential direct and indirect removed containers to the base URI obtained from the provided
* {@link EObject old owner} and {@link EStructuralFeature old feature}. If the object is still contained in a resource
* its URI is computed as usual and the old owner and old feature are ignored. In both cases, the resulting URI can
* optionally be resolved against the URI of the resource which does or did contain the object in question.
*
* @param oldOwner
* The owner object that is assumed to having contained the given object before it was removed.
* @param oldFeature
* The feature through which the old owner did contain the given object before it was removed.
* @param eObject
* The object to be handled.
* @param resolve
* Indicates whether the object's URI should be resolved against the URI of the resource which contains the
* provided model object. This is useful is cases where the native model object URI evaluates in some sort of
* fragment-based URI which does not contain any information about the resource that contains the model
* object (e.g., hb:/#//MyComponent/MyParameterValue). By setting resolve to true, such fragment-based URIs
* will be automatically expanded to a URI that starts with the URI of the model object's resource and is
* followed by the fragment of the model object's native URI (e.g.,
* platform:/resource/MyProject/MyResource/#//MyComponent/MyParameterValue).
* @return The URI representing the provided object.
*/
URI getURI(EObject oldOwner, EStructuralFeature oldFeature, EObject eObject, boolean resolve);
/**
* Creates a {@link URI} from given <code>uriLiteral</code> that refers to an instance of given {@link EClass object
* type}. This method is typically called during deserialization of resources when it comes to creating proxy URIs from
* serialized representations of cross-document references to objects in other resources.
* <p>
* Clients may implement/override this method when they require URIs with custom formats to be created
* </p>
*
* @param uriLiteral
* The string representation of the URI to be created.
* @param eClass
* The type of object that the URI to be created is supposed to refer to.
* @return The URI corresponding to given <code>uriLiteral</code>.
*/
URI createURI(String uriLiteral, EClass eClass);
/**
* Returns a {@link URI} representing an HREF to given {@link EObject} stored in underlying {@link Resource}. This
* method is typically called during serialization of resources when it comes to creating serializable representations
* of cross-document references for objects being referenced from other resources.
* <p>
* Clients may implement/override this method when they require HREFs with custom formats to be created.
* </p>
*
* @param eObject
* The object for which the HREF URI is to be created.
* @return The HREF URI to this object from this resource.
*/
URI getHREF(EObject eObject);
/**
* Returns the normalized form of the given {@link URI} fragment.
* <p>
* This may, in theory, do absolutely anything. The general idea behind this feature is to support resources in which
* the URI fragments used to identify objects can have manifold forms. The URI fragments that refer to a given object
* can then no longer be assumed to be always the same. Instead they may have alternative forms and look differently
* from case to case (e.g., have an additional postfix in simple cases, or a completely different format in more
* advanced cases). The URI fragment normalization enables such manifold URI fragments to be converted into a common
* base form and make them comparable. There is no general assumption of what normalized URI fragments should look like
* except for that they always must evaluate to the same string when the original URI fragments refer to the same
* object.
* </p>
* <p>
* It is important to emphasize that normalization can result in loss of information. The normalized URI fragment should
* generally be used only for the comparison of the identities of the objects being referred to.
* </p>
*
* @param uriFragment
* The URI fragment to normalize.
* @return The URI fragment in its normalized form, or the original URI fragment in case it already was normalized or
* the underlying resource type does not support alternative forms of URI fragments.
*/
String nomalizeURIFragment(String uriFragment);
/**
* Determines whether or not the given URI string represents a valid URI.
*
* @param uri
* The URI string to be validated.
* @return {@link Diagnostic#OK_INSTANCE} if given URI string is a valid URI or a {@link Diagnostic} with complementary
* information on error otherwise.
*/
Diagnostic validateURI(String uri);
/**
* Returns the entries of the xsi:schemaLocation attribute to be added to the resulting XML document when the underlying
* resource is saved.
* <p>
* This method enables the schema locations that are added to the serialized XML/XMI document to be explicitly
* controlled through the underlying resource instead of having them derived and inserted implicitly according to the
* EPackages that the serialized model elements stem from. Such resource-driven schema location entries, if present,
* override and replace all EPackage-driven schema location serialization entries.
* </p>
*
* @param options
* The save options.
* @return The schema location entries to be added to the resulting XML document when the underlying resource is saved.
* @see ExtendedXMLSaveImpl#addNamespaceDeclarations()
* @see #getDefaultSaveOptions()
*/
Map<String, String> getSchemaLocationEntries(Map<?, ?> options);
/**
* Augments given {@link InternalEObject proxy} to a context-aware proxy by adding key/value pairs that contain the
* target {@link IMetaModelDescriptor metamodel descriptor} and a context {@link URI} to the {@link URI#query() query
* string} of the proxy URI. Those are required to support the resolution of proxified references between objects from
* different metamodels and to honor the {@link IResourceScope resource scope} of the proxy URI when it is being
* resolved.
*
* @param proxy
* The proxy to be handled.
* @see #trimProxyContextInfo(URI)
*/
void augmentToContextAwareProxy(EObject proxy);
/**
* If given {@link URI proxy URI} contains proxy context-related key/value pairs on its {@link URI#query() query
* string}, returns the URI formed by removing those key/value pairs or removing the query string entirely in case that
* no other key/value pairs exist; returns given proxy URI unchanged, otherwise.
*
* @param proxyURI
* The context-aware proxy URI to be handled.
* @return The trimmed proxy URI.
* @see #augmentToContextAwareProxy(EObject)
*/
URI trimProxyContextInfo(URI proxyURI);
}