blob: cab440a5e2b4d5e23a42203361f2aa3bf9776aa4 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2002, 2004 IBM Corporation 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:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.emf.core.internal.util;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.ENamedElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.osgi.framework.Bundle;
import org.eclipse.gmf.runtime.common.core.util.Trace;
import org.eclipse.gmf.runtime.emf.core.EventTypes;
import org.eclipse.gmf.runtime.emf.core.IValidationStatus;
import org.eclipse.gmf.runtime.emf.core.edit.MDestroyOption;
import org.eclipse.gmf.runtime.emf.core.edit.MEditingDomain;
import org.eclipse.gmf.runtime.emf.core.edit.MRunnable;
import org.eclipse.gmf.runtime.emf.core.internal.commands.MCommand;
import org.eclipse.gmf.runtime.emf.core.internal.commands.MSLAbandonActionCommand;
import org.eclipse.gmf.runtime.emf.core.internal.commands.MSLEventCommand;
import org.eclipse.gmf.runtime.emf.core.internal.commands.MSLProxyCommand;
import org.eclipse.gmf.runtime.emf.core.internal.domain.MSLEditingDomain;
import org.eclipse.gmf.runtime.emf.core.internal.index.MSLReferenceVisitor;
import org.eclipse.gmf.runtime.emf.core.internal.plugin.MSLDebugOptions;
import org.eclipse.gmf.runtime.emf.core.internal.plugin.MSLPlugin;
import org.eclipse.gmf.runtime.emf.core.internal.resources.MSLResource;
import org.eclipse.gmf.runtime.emf.core.internal.services.metamodel.MetamodelSupportService;
import org.eclipse.gmf.runtime.emf.core.services.metamodel.IMetamodelSupport;
import org.eclipse.gmf.runtime.emf.core.util.EObjectUtil;
import org.eclipse.gmf.runtime.emf.core.util.MetaModelUtil;
/**
* Some internal utility classes.
*
* @author rafikj
*/
public class MSLUtil {
private final static Charset xmiCharset = Charset
.forName(MSLConstants.XMI_ENCODING);
// A char ch is encoded as itself if (nonEncodedMin <= ch && ch <=
// nonEncodedMax && same[ch - sameMin]).
private final static boolean[] nonEncoded;
private final static char nonEncodedMin;
private final static char nonEncodedMax;
private final static char[] hexChars = "0123456789abcdef".toCharArray(); //$NON-NLS-1$
static {
char[] sameChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.!~*'()".toCharArray(); //$NON-NLS-1$
int len = sameChars.length;
char min = '0';
char max = '0';
int i;
char c;
for (i = 0; i < len; ++i) {
c = sameChars[i];
if (min > c)
min = c;
if (max < c)
max = c;
}
nonEncoded = new boolean[max - min + 1];
nonEncodedMin = min;
nonEncodedMax = max;
for (i = 0; i < len; ++i)
nonEncoded[sameChars[i] - min] = true;
}
/**
* Get the meta-model of an EMF object.
*/
public static IMetamodelSupport getMetaModel(EObject eObject) {
if (eObject instanceof ENamedElement) {
EObject root = EcoreUtil.getRootContainer(eObject);
if (root instanceof EPackage)
return MetamodelSupportService.getInstance().getMetamodelSupport(
(EPackage) root);
}
IMetamodelSupport metaModel = null;
EPackage ePackage = null;
for (EObject current = eObject; (metaModel == null)
&& (current != null); current = current.eContainer()) {
ePackage = current.eClass().getEPackage();
metaModel = MetamodelSupportService.getInstance()
.getMetamodelSupport(ePackage);
}
return metaModel;
}
/**
* Create an EMF object instance given its EClass.
*/
public static EObject create(MSLEditingDomain domain, EClass eClass,
boolean sendEvents) {
EObject eObject = eClass.getEPackage().getEFactoryInstance().create(
eClass);
domain.getContentAdapter().listenToModifications(eObject);
if (sendEvents)
sendCreateEvent(domain, eObject);
return eObject;
}
/**
* Send a create event.
*/
public static void sendCreateEvent(MSLEditingDomain domain, EObject eObject) {
Notification createNotification = new ENotificationImpl(
(InternalEObject) eObject, EventTypes.CREATE,
(EStructuralFeature) null, (Object) null, (Object) null, -1);
Notification uncreateNotification = new ENotificationImpl(
(InternalEObject) eObject, EventTypes.UNCREATE,
(EStructuralFeature) null, (Object) null, (Object) null, -1);
execute(domain, MSLEventCommand.create(domain, createNotification,
uncreateNotification));
}
/**
* Destroys an EMF ebject.
*/
public static void destroy(MSLEditingDomain domain, EObject eObject,
int options) {
EObject container = eObject.eContainer();
if (container == null)
return;
IMetamodelSupport metaModel = getMetaModel(container);
if ((metaModel != null) && (!metaModel.canDestroy(eObject)))
return;
eObject.eNotify(new ENotificationImpl(
(InternalEObject) eObject, EventTypes.PRE_DESTROY,
(EStructuralFeature) null,
eObject, eObject));
Resource resource = container.eResource();
teardownContainment(domain, eObject, options);
container = eObject.eContainer();
if (container != null) {
String uriFragment = null;
if (((options & MDestroyOption.MAKE_PROXY) != 0)
&& (resource != null))
uriFragment = resource.getURIFragment(eObject);
EReference reference = eObject.eContainmentFeature();
if (reference.isMany())
((Collection) container.eGet(reference)).remove(eObject);
else
container.eSet(reference, null);
if ((options & MDestroyOption.NO_EVENTS) == 0)
sendDestroyEvent(domain, eObject);
if ((options & MDestroyOption.KEEP_REFERENCES) == 0)
teardownReferences(domain, eObject, container, options);
if (uriFragment != null) {
URI resourceURI = resource.getURI();
if (resourceURI != null) {
execute(domain, MSLProxyCommand.create(domain, eObject,
resourceURI.appendFragment(uriFragment)));
domain.sendNotification(eObject, EventTypes.UNRESOLVE);
}
}
}
}
/**
* Abandons the current write action in the specified editing
* <code>domain</code>, if any. The action is not immediately rolled back,
* but will rollback when it finishes.
*
* @param domain the editing domain
* @param message the localized reason for the action abandonment
*/
public static void abandon(MEditingDomain domain, String message) {
if (domain instanceof MSLEditingDomain) {
MSLEditingDomain mslDomain = (MSLEditingDomain) domain;
if (mslDomain.getUndoStack().isWriteActionInProgress()) {
MSLUtil.execute(mslDomain,
new MSLAbandonActionCommand(mslDomain, message));
}
}
}
/**
* Send a destroy event.
*/
public static void sendDestroyEvent(MSLEditingDomain domain, EObject eObject) {
Notification createNotification = new ENotificationImpl(
(InternalEObject) eObject, EventTypes.DESTROY,
(EStructuralFeature) null, (Object) null, (Object) null, -1);
Notification uncreateNotification = new ENotificationImpl(
(InternalEObject) eObject, EventTypes.UNDESTROY,
(EStructuralFeature) null, (Object) null, (Object) null, -1);
execute(domain, MSLEventCommand.create(domain, createNotification,
uncreateNotification));
}
/**
* Get the ID of an EMF object.
*/
public static String getID(EObject eObject) {
Resource resource = eObject.eResource();
String id = null;
if (resource == null)
id = MSLResource.getSavedID(eObject);
else if (resource instanceof XMLResource)
id = ((XMLResource) resource).getID(eObject);
if (id != null)
return id;
else
return MSLConstants.EMPTY_STRING;
}
/**
* Set the ID of an EMF object.
*/
public static void setID(EObject eObject, String id) {
Resource resource = eObject.eResource();
if (resource instanceof XMLResource)
((XMLResource) resource).setID(eObject, id);
}
/**
* Default implementation of the MSL proxy URI parser. Parsing of name.
*/
public static String getProxyName(EObject eObject) {
if (eObject == null)
return MSLConstants.EMPTY_STRING;
if (!eObject.eIsProxy())
return EObjectUtil.getName(eObject);
String name = MSLConstants.EMPTY_STRING;
String proxyQName = getProxyQName(eObject);
if ((proxyQName != null) && (proxyQName.length() > 0)) {
String[] segments = proxyQName
.split(MSLConstants.QUALIFIED_NAME_SEPARATOR);
name = segments[segments.length - 1];
}
if ((name == null) || (name.length() == 0)) {
EAttribute nameAttribute = MetaModelUtil.getNameAttribute(eObject
.eClass());
if (nameAttribute != null) {
name = (String) eObject.eGet(nameAttribute);
if (name != null)
return name;
}
return MSLConstants.EMPTY_STRING;
}
return name;
}
/**
* Default implementation of the MSL proxy URI parser. Parsing of qualified
* name.
*/
public static String getProxyQName(EObject eObject) {
if (eObject == null)
return MSLConstants.EMPTY_STRING;
if (!eObject.eIsProxy())
return EObjectUtil.getQName(eObject, true);
String proxyQName = MSLConstants.EMPTY_STRING;
String uriFragment = EcoreUtil.getURI(eObject).fragment();
int index = uriFragment.indexOf(MSLConstants.FRAGMENT_SEPARATOR);
if (index != -1) {
proxyQName = decodeQName(uriFragment.substring(index + 1,
uriFragment.length()));
}
if ((proxyQName == null) || (proxyQName.length() == 0)) {
EAttribute qNameAttribute = MetaModelUtil.getQNameAttribute(eObject
.eClass());
if (qNameAttribute != null) {
String qualifiedName = (String) eObject.eGet(qNameAttribute);
if (qualifiedName != null)
return qualifiedName;
else
return MSLConstants.EMPTY_STRING;
}
}
return proxyQName;
}
/**
* Default implementation of the MSL proxy URI parser. Parsing of ID.
*/
public static String getProxyID(EObject eObject) {
if (eObject == null)
return MSLConstants.EMPTY_STRING;
if (!eObject.eIsProxy())
return getID(eObject);
String uriFragment = EcoreUtil.getURI(eObject).fragment();
int index = uriFragment.indexOf(MSLConstants.FRAGMENT_SEPARATOR);
return index != -1 ? uriFragment.substring(0, index)
: uriFragment;
}
/**
* Default implementation of the MSL proxy URI parser. Parsing of Class ID.
*/
public static String getProxyClassID(EObject eObject) {
return eObject == null ? MSLConstants.EMPTY_STRING
: MetaModelUtil.getID(eObject.eClass());
}
/**
* Resolve a proxy object.
*/
public static EObject resolve(MSLEditingDomain domain,
EObject eObject, boolean resolve) {
if (eObject == null)
return null;
if (!eObject.eIsProxy())
return eObject;
if (resolve) {
EObject resolved = EcoreUtil.resolve(eObject, domain
.getResourceSet());
return (resolved.eIsProxy() ? null
: resolved);
}
return null;
}
/**
* Can an instance of class1 contain an instance of class2.
*/
public static boolean canContain(EClass class1, EClass class2, Set visited) {
IMetamodelSupport metaModel = MSLUtil.getMetaModel(class1);
{
Iterator i = class1.getEAllReferences().iterator();
while (i.hasNext()) {
EReference reference = (EReference) i.next();
if (reference.isContainment()) {
EClass eType = (EClass) reference.getEType();
if ((eType.equals(class2)) || (eType.isSuperTypeOf(class2))) {
if (metaModel == null)
return true;
else if (metaModel
.canContain(class1, reference, class2))
return true;
}
}
}
}
if ((visited != null) && (!visited.contains(class1))) {
visited.add(class1);
Iterator i = class1.getEAllReferences().iterator();
while (i.hasNext()) {
EReference reference = (EReference) i.next();
if (reference.isContainment()) {
EClass eType = (EClass) reference.getEType();
if (canContain(eType, class2, visited))
return true;
}
}
}
return false;
}
/**
* Execute an MSL command.
*/
public static void execute(MSLEditingDomain domain, MCommand command) {
if (!command.canExecute()) {
RuntimeException e = new IllegalStateException(
"cannot execute EMF command"); //$NON-NLS-1$
Trace.throwing(MSLPlugin.getDefault(),
MSLDebugOptions.EXCEPTIONS_THROWING, MSLUtil.class,
"execute", e); //$NON-NLS-1$
throw e;
}
command.execute();
domain.getUndoStack().add(command);
}
/**
* Resolve the file path of a resource.
*/
public static String getFilePath(Resource resource) {
return getFilePath(resource.getResourceSet(), resource.getURI());
}
/**
* Resolve a URI to a file path.
*/
public static String getFilePath(ResourceSet resourceSet, URI uri) {
String filePath = null;
if (uri == null) {
filePath = MSLConstants.EMPTY_STRING;
return filePath;
}
if ((resourceSet != null)
&& (MSLConstants.PATH_MAP_SCHEME.equals(uri.scheme())))
uri = resourceSet.getURIConverter().normalize(uri);
if (uri.isFile())
filePath = uri.toFileString();
else if (MSLConstants.PLATFORM_SCHEME.equals(uri.scheme())) {
String[] segments = uri.segments();
if (segments.length > 2) {
if (MSLConstants.RESOURCE.equals(segments[0])) {
IProject project = null;
IWorkspace workspace = ResourcesPlugin.getWorkspace();
if (workspace != null) {
IWorkspaceRoot root = workspace.getRoot();
if (root != null)
project = root.getProject(URI.decode(segments[1]));
}
if ((project != null) && (project.exists())) {
StringBuffer path = new StringBuffer();
path.append(project.getLocation().toString());
for (int i = 2; i < segments.length; i++) {
path.append(MSLConstants.PATH_SEPARATOR);
path.append(URI.decode(segments[i]));
}
filePath = path.toString();
}
} else if (MSLConstants.PLUGIN.equals(segments[0])) {
Bundle bundle = Platform.getBundle(URI.decode(segments[1]));
if (bundle != null) {
StringBuffer path = new StringBuffer();
for (int i = 2; i < segments.length; i++) {
path.append(URI.decode(segments[i]));
path.append(MSLConstants.PATH_SEPARATOR);
}
URL url = bundle.getEntry(path.toString());
if (url != null) {
try {
url = Platform.resolve(url);
if (url != null) {
if (MSLConstants.FILE_SCHEME.equals(url
.getProtocol()))
filePath = url.getPath();
}
} catch (IOException e) {
Trace.catching(MSLPlugin.getDefault(),
MSLDebugOptions.EXCEPTIONS_CATCHING,
MSLUtil.class, "getFilePath", e); //$NON-NLS-1$
}
}
}
}
}
}
if (filePath == null)
filePath = MSLConstants.EMPTY_STRING;
else {
if (filePath.indexOf(MSLConstants.INVALID_PATH) == -1) {
if (File.separatorChar != MSLConstants.PATH_SEPARATOR)
filePath = filePath.replace(MSLConstants.PATH_SEPARATOR,
File.separatorChar);
} else
filePath = MSLConstants.EMPTY_STRING;
}
return filePath;
}
/**
* Is resource modifiable?
*/
public static boolean isModifiable(Resource resource) {
URI uri = resource.getURI();
if (uri != null) {
File file = null;
if (uri.isFile())
file = new File(uri.toFileString());
else
file = new File(getFilePath(resource));
return ((file == null) || (!file.exists()) || (file.canWrite()));
}
return true;
}
/**
* Gets resource of an EObject given its URI or create it if not there.
*/
public static Resource getResource(MSLEditingDomain domain, EObject eObject) {
if (eObject.eIsProxy()) {
URI uri = EcoreUtil.getURI(eObject).trimFragment();
ResourceSet resourceSet = domain.getResourceSet();
Resource resource = resourceSet.getResource(uri, false);
if (resource == null)
resource = resourceSet.createResource(uri);
return resource;
} else
return eObject.eResource();
}
/**
* Post-process resource
*/
public static void postProcessResource(final Resource resource) {
if (resource instanceof MSLResource) {
final MSLEditingDomain domain = (MSLEditingDomain) MEditingDomain
.getEditingDomain(resource);
if (domain != null) {
domain.runAsUnchecked(new MRunnable() {
public Object run() {
List resourceContents = resource.getContents();
if (resourceContents != null) {
for (Iterator i = resourceContents.iterator(); i
.hasNext();) {
EObject root = (EObject) i.next();
if ((root != null)
&& (root.eResource() == resource)) {
IMetamodelSupport metaModel = MSLUtil
.getMetaModel(root);
if (metaModel != null)
metaModel.postProcess(root);
}
}
}
domain.getResourceIndexer()
.registerReferences(resource);
return null;
}
});
}
}
}
/**
* Process references and update reference maps.
*/
public static void registerReferences(MSLEditingDomain domain,
EObject eObject, EReference reference, List newObjects,
List oldObjects) {
if (reference.isContainment()) {
if (!newObjects.isEmpty()) {
Iterator i = newObjects.iterator();
while (i.hasNext()) {
EObject newObject = (EObject) i.next();
domain.getObjectIndexer().registerReferences(eObject,
newObject);
}
}
if (!oldObjects.isEmpty()) {
Iterator i = oldObjects.iterator();
while (i.hasNext()) {
EObject oldObject = (EObject) i.next();
domain.getObjectIndexer().deregisterReferences(eObject,
oldObject);
}
}
} else {
if (!newObjects.isEmpty()) {
Iterator i = newObjects.iterator();
while (i.hasNext()) {
EObject newObject = (EObject) i.next();
// registers reference in reverse reference map.
domain.getObjectIndexer().registerReference(eObject,
newObject, reference);
}
}
if (!oldObjects.isEmpty()) {
Iterator i = oldObjects.iterator();
while (i.hasNext()) {
EObject oldObject = (EObject) i.next();
// deregisters reference in reverse reference
// map.
domain.getObjectIndexer().deregisterReference(eObject,
oldObject, reference);
}
}
}
}
/**
* Returns all of the children of the validation <code>status</code> that
* indicate violated constraints (i.e., problems). These will be some
* combination of errors, warnings, and informational messages. No reports
* of successful constraint evaluations are included
*
* @param status
* the validation status (may be <code>null</code> or a
* non-multi-status)
* @return the validation problems (as {@link IValidationStatus}es. This
* list is safely modifiable
*/
public static List getValidationProblems(IStatus status) {
final List result;
if ((status == null) || status.isOK()) {
// not problems to report
result = new java.util.ArrayList();
} else if (!status.isMultiStatus()) {
// a single problem, or none if it is OK
result = new java.util.ArrayList();
if (status instanceof IValidationStatus) {
result.add(status);
} // otherwise, the result is an empty list
} else {
// potentially multiple problems to report
IStatus[] children = status.getChildren();
result = new java.util.ArrayList(children.length);
for (int i = 0; i < children.length; i++) {
IStatus next = children[i];
if ((next instanceof IValidationStatus) && !next.isOK()) {
result.add(next);
}
}
}
return result;
}
/**
* Encodes the specified qualified name.
*
* @param qName
* The qualified name to be encoded.
* @return The encoded qualified name.
*/
public static String encodeQName(String qName) {
return appendQName(new StringBuffer(), qName).toString();
}
private static final String colonEscaped = "%3A"; //$NON-NLS-1$
/**
* Appends an encoded version of the specified qualified name to the
* specified buffer. All excluded characters, such as space and
* <code>#</code>, are escaped, as are <code>/</code> and
* <code>?</code>.
*
* @param buffer
* The buffer to which to append.
* @param qName
* The qualified name to be encoded.
* @return The buffer.
*/
public static StringBuffer appendQName(StringBuffer buffer, String qName) {
String[] segments = qName.split(MSLConstants.QUALIFIED_NAME_SEPARATOR);
for (int i = 0; i < segments.length; i++) {
String encodedSegment = URI.encodeSegment(segments[i], true);
for (int j = 0, length = encodedSegment.length(); j < length; j++) {
char c = encodedSegment.charAt(j);
if (':' == c) {
// EMF treats :'s as special characters in fragments...
buffer.append(colonEscaped);
} else {
buffer.append(c);
}
}
if (i + 1 < segments.length) {
buffer.append(MSLConstants.PATH_SEPARATOR);
}
}
return buffer;
}
private static final String pathDelimiter = String
.valueOf(MSLConstants.PATH_SEPARATOR);
/**
* Decodes the specified qualified name by replacing each three-digit escape
* sequence by the character that it represents.
*
* @param qName
* The qualified name to be decoded.
* @return The decoded qualified name.
*/
public static String decodeQName(String qName) {
StringBuffer buffer = new StringBuffer();
for (StringTokenizer st = new StringTokenizer(qName, pathDelimiter); st
.hasMoreTokens();) {
buffer.append(URI.decode(st.nextToken()));
if (st.hasMoreTokens())
buffer.append(MSLConstants.QUALIFIED_NAME_SEPARATOR);
}
return buffer.toString();
}
/**
* Encode a URL to avoid corrupt strings in XML files.
*/
public static String encodeURL(String url) {
int len = url.length();
// add a little (6.25%) to leave room for some expansion during encoding
len += len >>> 4;
return appendURL(new StringBuffer(len), url).toString();
}
/**
* Encode a URL to avoid corrupt strings in XML files.
*/
public static StringBuffer appendURL(StringBuffer buffer, String url) {
ByteBuffer byteBuffer = xmiCharset.encode(url);
int limit = byteBuffer.limit();
byte[] bytes;
int offset = 0;
if (byteBuffer.hasArray()) {
bytes = byteBuffer.array();
offset = byteBuffer.arrayOffset();
} else {
byteBuffer.get(bytes = new byte[limit], 0, limit);
}
while (--limit >= 0) {
char c = (char) bytes[offset++];
if (c == ' ')
c = '+';
else if (c < nonEncodedMin || nonEncodedMax < c
|| !nonEncoded[c - nonEncodedMin]) {
buffer.append('%');
buffer.append(hexChars[(c >>> 4) & 0xF]);
c = hexChars[c & 0xF];
}
buffer.append(c);
}
return buffer;
}
/**
* Decode an encoded URL.
*/
public static String decodeURL(String url) {
int len = url.length();
byte[] bytes = new byte[len];
int size = 0;
boolean simple = true;
for (int i = 0; i < len; ++i) {
byte b = (byte) url.charAt(i);
if (b == '+') {
simple = false;
b = ' ';
} else if (b == '%') {
simple = false;
i += 2;
if (i >= len)
break;
b = getByte(url.charAt(i - 1), url.charAt(i));
}
bytes[size++] = b;
}
String result = xmiCharset.decode(ByteBuffer.wrap(bytes, 0, size))
.toString();
if (simple && result.equals(url))
result = url; // reuse the input string
return result;
}
/**
* Decode chars.
*/
private static byte getByte(char c1, char c2) {
byte b = getByte(c1);
b <<= 4;
b += getByte(c2);
return b;
}
/**
* Decode char.
*/
private static byte getByte(char c) {
byte b = (byte) c;
if (!Character.isDigit(c)) {
b = (byte) Character.toLowerCase(c);
b -= 'a' - 10;
}
b -= '0';
b &= 0xF;
return b;
}
/**
* Teardown containment of an EMF object.
*/
public static void teardownContainment(MSLEditingDomain domain,
EObject eObject, int options) {
List actions = new ArrayList();
Iterator i = eObject.eClass().getEAllContainments().iterator();
while (i.hasNext()) {
EReference reference = (EReference) i.next();
if ((reference.isChangeable()) && (eObject.eIsSet(reference))) {
actions
.add(new TeardownAction(domain, eObject, reference, null));
}
}
Iterator j = actions.iterator();
while (j.hasNext())
((TeardownAction) j.next()).execute();
}
/**
* Teardown references to and from an EMF object.
*/
public static void teardownReferences(final MSLEditingDomain domain,
final EObject eObject, final EObject container, final int options) {
final List actions = new ArrayList();
Iterator i = eObject.eClass().getEAllReferences().iterator();
while (i.hasNext()) {
EReference reference = (EReference) i.next();
if ((reference.isChangeable()) && (!reference.isContainer())
&& (!reference.isContainment()) && (eObject.eIsSet(reference))) {
actions
.add(new TeardownAction(domain, eObject, reference, null));
}
}
MSLReferenceVisitor visitor = new MSLReferenceVisitor(domain, eObject) {
protected void visitedReferencer(EReference reference,
EObject referencer) {
actions.add(new TeardownAction(domain, referencer, reference,
eObject));
}
};
visitor.visitReferencers();
Iterator j = actions.iterator();
while (j.hasNext())
((TeardownAction) j.next()).execute();
}
/**
* Helper class used by teardown.
*/
private static class TeardownAction {
private EObject container = null;
private EReference reference = null;
private EObject object = null;
/**
* Constructor.
*/
public TeardownAction(MSLEditingDomain domain, EObject container,
EReference reference, EObject object) {
this.container = container;
this.reference = reference;
this.object = object;
}
/**
* Execute the action.
*/
public void execute() {
if (object == null) {
if (container.eIsSet(reference)) {
if (reference.isMany()) {
List objects = (List) container.eGet(reference);
if (reference.isContainment()) {
if (!objects.isEmpty()) {
Collection destroyed = new ArrayList(objects);
for (Iterator i = destroyed.iterator(); i
.hasNext();)
EObjectUtil.destroy((EObject) i.next());
}
} else {
if (!objects.isEmpty()) {
Collection detached = new ArrayList(objects);
for (Iterator i = detached.iterator(); i
.hasNext();) {
EObject eObject = (EObject) i.next();
((Collection) container.eGet(reference))
.remove(eObject);
}
}
}
} else {
if (reference.isContainment()) {
object = (EObject) container.eGet(reference);
if (object != null)
EObjectUtil.destroy(object);
} else
container.eSet(reference, null);
}
}
} else {
if (reference.isContainment())
EObjectUtil.destroy(object);
else {
if (reference.isMany())
((Collection) container.eGet(reference)).remove(object);
else
container.eSet(reference, null);
}
}
}
}
/**
* Fix references.
*/
public static void fixReferences(EObject eObject, EClass newClass,
EObject newObject, EReference reference, EClass type,
EObject referencer) {
if (reference.isMany()) {
List list = (List) referencer.eGet(reference);
int position = list.indexOf(eObject);
((Collection) referencer.eGet(reference)).remove(eObject);
if ((reference.getEOpposite() == null)
&& ((newClass == type) || (type.isSuperTypeOf(newClass))))
((List) referencer.eGet(reference)).add(position, newObject);
} else if ((newClass == type) || (type.isSuperTypeOf(newClass)))
referencer.eSet(reference, newObject);
else
referencer.eSet(reference, null);
}
/**
* Replace references.
*/
public static void replaceReferences(EObject referenced,
EObject replacement, List ignoredObjects, EReference reference,
EObject referencer) {
// Don't fix references in elements that are in or
// contained by elements in the ignoreElements list.
boolean ignore = false;
for (Iterator k = ignoredObjects.iterator(); k.hasNext();) {
EObject ignored = (EObject) k.next();
if (EObjectUtil.contains(ignored, referencer)) {
ignore = true;
break;
}
}
if (!ignore) {
if (reference.isMany()) {
EList list = (EList) referencer.eGet(reference);
int existingIndex = list.indexOf(replacement);
if (existingIndex < 0) {
// Replacement not already in the list. Do nothing if the
// replacement is already in the list,
// because this means it was already added,
// e.g., adding to a subset will add to the superset
// feature.
int index = list.indexOf(referenced);
list.add(index, replacement);
}
} else
referencer.eSet(reference, replacement);
}
}
/**
* Safely add object to an EList.
*/
public static void addObject(EList ownerList, Object object, int position) {
int oldPosition = ownerList.indexOf(object);
if (oldPosition != -1) {
if ((position != -1) && (position < ownerList.size()))
ownerList.move(position, oldPosition);
} else if (position == -1)
ownerList.add(object);
else if (position <= ownerList.size())
ownerList.add(position, object);
else
ownerList.add(object);
}
/**
* Safely add a collection of objects to an EList.
*/
public static void addObjects(EList ownerList, Collection objects,
int position) {
if (position == -1)
ownerList.addAll(objects);
else if (position <= ownerList.size())
ownerList.addAll(position, objects);
else
ownerList.addAll(objects);
}
/**
* Safely add a collection of objects to an EList. Caller need to pass a
* List of objects to ensure order preservation.
*/
public static void addObjects(EList ownerList, Collection objects,
int[] positions) {
int index = 0;
for (Iterator i = objects.iterator(); i.hasNext();) {
int position = -1;
if (index < positions.length)
position = positions[index];
addObject(ownerList, i.next(), position);
index++;
}
}
}